并发编程(多线程)-可见性、有序性、原子性问题

news2024/11/24 17:15:59

可见性

可见性概念

可见性(Visibility):是指一个线程对共享变量进行修改,另一个先立即得到修改后的最新值

可见性演示

案例演示:一个线程根据boolean类型的标记flag,while循环,另一个线程改变这个flag变量的值,另一个线程并不会停止循环

/**
 * 案例演示:
 * 一个线程对共享变量的修改,另一个线程不能立即得到最新值
 */
public class Test01Visibility {
    // 多个线程都会访问的数据,我们称为线程的共享数据
    private static boolean run = true;

    public static void main(String[] args) throws InterruptedException {
        Thread t1 = new Thread(() -> {
            while (run) {
            }
        });
        t1.start();
        Thread.sleep(1000);
        Thread t2 = new Thread(() -> {
            run = false;
            System.out.println("时间到,线程2设置为false");
        });
        t2.start();
    }
}

小结

并发编程时,会出现可见性问题,当一个线程对共享变量进行了修改,另外的线程并没有立即看修改后的最新值

原子性

原子性概念

原子性(Atomicity):在一次或多次操作中,要么所有的操作都执行并且不会受其他因素干扰而中 断,要么所有的操作都不执行。

原子性演示

案例演示:5个线程各执行1000 i++;
import java.util.ArrayList;
    /**
     案例演示:5个线程各执行1000次 i++;
     */
    public class Test02Atomicity {
        private static int number = 0;
        public static void main(String[] args) throws InterruptedException {
            Runnable increment = () -> {
                for (int i = 0; i < 1000; i++) {
                    number++;
                }
            };
            ArrayList<Thread> ts = new ArrayList<>();
            for (int i = 0; i < 5; i++) {
                Thread t = new Thread(increment);
                t.start();
                ts.add(t);
            }
            for (Thread t : ts) {
                t.join();
            }
            System.out.println("number = " + number);
        }
    }
使用javap反汇编class文件,得到下面的字节码指令:
其中,对于 number++ 而言(number 为静态变量),实际会产生如下的 JVM 字节码指令:
9: getstatic #12 // Field number:I
12: iconst_1
13: iadd
14: putstatic #12 // Field number:I

由此可见number++是由多条语句组成,以上多条指令在一个线程的情况下是不会出问题的,但是在多 线程情况下就可能会出现问题。比如一个线程在执行13: iadd时,另一个线程又执行9: getstatic。会导致两次number++,实际上只加了1

小结

并发编程时,会出现原子性问题,当一个线程对共享变量操作到一半时,另外的线程也有可能来操作共 享变量,干扰了前一个线程的操作。

有序性

有序性概念

有序性(Ordering):是指程序中代码的执行顺序,Java在编译时和运行时会对代码进行优化,会导致 程序最终的执行顺序不一定就是我们编写代码时的顺序。
public static void main(String[] args) {
    int a = 10;
    int b = 20;
}

有序性演示

jcstressjava并发压测工具。https://wiki.openjdk.java.net/display/CodeTools/jcstress
修改pom文件,添加依赖:
<dependency>
    <groupId>org.openjdk.jcstress</groupId>
    <artifactId>jcstress-core</artifactId>
    <version>${jcstress.version}</version>
</dependency>
代码
Test03Orderliness.java
import org.openjdk.jcstress.annotations.*;
    import org.openjdk.jcstress.infra.results.I_Result;
    @JCStressTest
    @Outcome(id = {"1", "4"}, expect = Expect.ACCEPTABLE, desc = "ok")
    @Outcome(id = "0", expect = Expect.ACCEPTABLE_INTERESTING, desc = "danger")
    @State
    public class Test03Orderliness {
        int num = 0;
        boolean ready = false;
        // 线程一执行的代码
        @Actor
        public void actor1(I_Result r) {
            if(ready) {
                r.r1 = num + num;
            } else {
                r.r1 = 1;
            }
        }
        // 线程2执行的代码
        @Actor
        public void actor2(I_Result r) {
            num = 2;
            ready = true;
        }
    }
I_Result 是一个对象,有一个属性 r1 用来保存结果,在多线程情况下可能出现几种结果?
情况1:线程1先执行actor1,这时ready = false,所以进入else分支结果为1。
情况2:线程2执行到actor2,执行了num = 2;和ready = true,线程1执行,这回进入 if 分支,结果为 4。
情况3:线程2先执行actor2,只执行num = 2;但没来得及执行 ready = true,线程1执行,还是进入 else分支,结果为1。
运行测试:
mvn clean install
java -jar target/jcstress.jar

小结

程序代码在执行过程中的先后顺序,由于Java在编译期以及运行期的优化,导致了代码的执行顺序未必 就是开发者编写代码时的顺序。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1214200.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于鸽群算法优化概率神经网络PNN的分类预测 - 附代码

基于鸽群算法优化概率神经网络PNN的分类预测 - 附代码 文章目录 基于鸽群算法优化概率神经网络PNN的分类预测 - 附代码1.PNN网络概述2.变压器故障诊街系统相关背景2.1 模型建立 3.基于鸽群优化的PNN网络5.测试结果6.参考文献7.Matlab代码 摘要&#xff1a;针对PNN神经网络的光滑…

Android设计模式--策略模式

每天都要完成一个小目标 一&#xff0c;定义 策略模式定义了一系列的算法&#xff0c;并将每一个算法封装起来&#xff0c;而且使他们还可以相互替换。策略模式让算法独立于使用它的客户而独立变化 什么意思呢&#xff1f;在我们平时的开发中&#xff0c;难免会遇到这种情况&…

保姆级fastDFS安装教程

一、软件准备 环境需要准备四个包&#xff0c;分别是&#xff1a; 1. libfastcommon_1.0.36 2. FastdfsFastdfs_v5.11 3. fastdfs-nginx-module5.11 4. nginxnginx-1.12.2 二、环境准备 安装perl环境&#xff0c;后续编译fastdfs会用到 yum -y install perl* yum -y ins…

MySQL数据库清理Relay_Log_File日志

背景 “Relay_Log_File” 是 MySQL 中用于复制的参数之一。在 MySQL 复制中&#xff0c;当一个服务器作为主服务器&#xff08;master&#xff09;时&#xff0c;它会将其更改写入二进制日志文件&#xff08;binary log file&#xff09;。而另一个服务器作为从服务器&#xf…

springboot--单元测试

单元测试 前言1、写测试要用的类2、写测试要用的类3、运行测试类4、spring-boot-starter-test默认提供了以下库4.1 junit54.1.1 DisplayName:为测试类或者测试方法设置展示名称4.1.2 BeforeAll&#xff1a;所有测试方法运行之前先运行这个4.1.3 BeforeEach&#xff1a;每个测试…

Vue3问题:如何实现拼图验证+邮箱登录功能?前后端!

前端功能问题系列文章&#xff0c;点击上方合集↑ 序言 大家好&#xff0c;我是大澈&#xff01; 本文约3500字&#xff0c;整篇阅读大约需要5分钟。 本文主要内容分三部分&#xff0c;第一部分是需求分析&#xff0c;第二部分是实现步骤&#xff0c;第三部分是问题详解。 …

给女朋友开发个小程序低价点外卖吃还能赚钱

前言 今天又是无聊的一天,逛了下GitHub,发现一个库里面介绍美团饿了吗外卖红包外卖优惠券,先领红包再下单。外卖红包优惠券,cps分成,别人领红包下单,你拿佣金。哇靠,那我岂不是可以省钱还可以赚钱,yyds。。。。想想都美好哈哈哈!!! 回到正题,这个是美团饿了么分销…

esp-01刷固件/下载软件到内部单片机的方法

此文章为转载&#xff0c;非原创 一、准备 需要准备三个东西&#xff1a; 1.esp模块。ESP-01 和 ESP-01s 的引脚及 flash 容量基本完全兼容&#xff0c;只是内部硬件设计粗糙与否的区别&#xff0c;所以理论上都适用。 2.官方固件。此部分可以从安信可官方教程中下载&#xff0…

python之使用深度学习创建自己的表情符号

目录 部署项目1、首先运行train.py训练模型2、接下运行gui.py测试 一、使用 CNN 进行面部情绪识别二、GUI 代码和表情符号映射 在这个深度学习项目中&#xff0c;我们将对人类面部表情进行分类&#xff0c;以过滤和映射相应的表情符号或头像。 数据集&#xff08;面部表情识别&…

提效神器!10%标注数据,比肩全量标注的模型效果!

不知道大家有没有遇到过数据标注成本高、周期长的困扰&#xff0c;有没有那么一种可能&#xff0c;精心标注少量的数据&#xff0c;配合大量的无标注数据&#xff0c;就能达到比肩全量标注的模型精度呢&#xff1f;是的&#xff0c;PaddleX就带来了这样一款提效神器——大模型半…

超级干货!如何挖公益SRC实战/SQL注入

目录 一、信息收集 二、实战演示 三、使用sqlmap进行验证 四、总结 一、信息收集 1.查找带有ID传参的网站&#xff08;可以查找sql注入漏洞&#xff09; inurl:asp idxx 2.查找网站后台&#xff08;多数有登陆框&#xff0c;可以查找弱口令&#xff0c;暴力破解等漏洞&…

第一百七十四回 如何创建扇形渐变背景

文章目录 1. 概念介绍2. 实现方法3. 代码与效果3.1 示例代码3.2 运行效果 4. 内容总结 我们在 上一章回中介绍了"如何创建线性渐变背景"相关的内容&#xff0c;本章回中将介绍" 如何创建扇形渐变背景"。闲话休提&#xff0c;让我们一起Talk Flutter吧。 …

打开GeoTIFF文件失败:Unknown field with tag

用QGIS输出的数据类型为UInt16的TIFF文件&#xff0c;无法在GIMP中打开。 GIMP消息提示&#xff1a; 调查 用ImageMagick打开TIFF文件&#xff0c;虽然会出现警告&#xff0c;但是最终还是打开了&#xff1a; 在ImageMagick中重新保存后&#xff0c;就可以用GIMP打开了。使用…

Mapstruct 搭配MP分页食用 - 参考自ballcat项目

参考自 ballcat 一键抵达&#xff1a; Gitee GitHub 场景 使用MyBatis Plus的selectPage方法进行分页查询之后&#xff0c;如果需要将Entity对象转换为Vo对象&#xff0c;需要从Page对象中取出集合列表&#xff0c;手动转换成Vo集合列表数据重新放进Page对象中。 取出集合 设置…

使用postman测试

第一步&#xff1a; 第二步&#xff1a; 第三步&#xff1a;添加请求 第四步&#xff1a;填写请求 代码实现自动关联的位置&#xff1a; 为相关联的接口设置环境&#xff1a; 使用设置的环境变量&#xff1a; 参数化实现测试&#xff1a;测试脚本中仅测试数据不一样&#xff…

[答疑]改善系统的性能,用得着业务建模吗

DDD领域驱动设计批评文集 做强化自测题获得“软件方法建模师”称号 《软件方法》各章合集 第五元素 2023-10-27 22:02 潘老师&#xff0c;请教一个实践中遇到的问题&#xff1a; 假设生产人员使用某个工具处理数据&#xff0c;需要10天时间&#xff1b;现在改进了这个工具…

Java排序算法之堆排序

图解 堆排序是一种常见的排序算法&#xff0c;它借助了堆这种数据结构。堆是一种完全二叉树&#xff0c;它可以分为两种类型&#xff1a;最大堆和最小堆。在最大堆中&#xff0c;每个结点的值都大于等于它的子结点的值&#xff0c;而在最小堆中&#xff0c;每个结点的值都小于等…

SpringSecurity6从入门到上天系列第六篇:解决这个问题为什么在引入SpringSecurity之后所有的请求都需要先做登录认证才可以进行访问呢

文章目录 问题引入 1&#xff1a;问题阐述 2&#xff1a;问题分析 一&#xff1a;从SpringBoot的自动装配 1&#xff1a;SpringBootApplication介绍 2&#xff1a;自动装配的核心方法 3&#xff1a;核心方法的调用路径 4&#xff1a;SpringSecurity核心配置 5&#xf…

PMP备考短期极限上岸攻略!

作为一位通过PMP考试成功上岸的3A人士&#xff0c;下面的文章包含了所有PMP考试的实用知识&#xff0c;是一本适合初学者的PMP备考攻略手册。如果你有意向了解或者报考PMP考试&#xff0c;这篇文章肯定会对你有很大的帮助&#xff01; 对于新手第一个需要知道的就是PMP是什么&…

【python】—— 控制语句和组合数据类型(其一)

&#x1f383;个人专栏&#xff1a; &#x1f42c; 算法设计与分析&#xff1a;算法设计与分析_IT闫的博客-CSDN博客 &#x1f433;Java基础&#xff1a;Java基础_IT闫的博客-CSDN博客 &#x1f40b;c语言&#xff1a;c语言_IT闫的博客-CSDN博客 &#x1f41f;MySQL&#xff1a…