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

目录

可见性

可见性概念

可见性演示

小结

原子性

原子性概念

原子性演示

小结

有序性

有序性概念

有序性演示

小结


可见性

可见性概念

可见性(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")@Statepublic class Test03Orderliness {int num = 0;boolean ready = false;// 线程一执行的代码@Actorpublic void actor1(I_Result r) {if(ready) {r.r1 = num + num;} else {r.r1 = 1;}}// 线程2执行的代码@Actorpublic 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.hqwc.cn/news/192804.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Python------列表 集合 字典 推导式(本文以 集合为主)

推导式&#xff1a; 推导式comprehensions&#xff08;又称解析式&#xff09;&#xff0c;是Python的一种独有特性。推导式是可以从一个数据序列 构建 另一个 新的数据序列&#xff08;一个有规律的列表或控制一个有规律列表&#xff09;的结构体。 共有三种推导&#xff…

【C++】类与对象(上)

目录 1. 面向过程和面向对象初步认识 2. 类的引入 3. 类的定义 4. 类的访问限定符及封装 4.1 访问限定符 4.2 封装 5. 类的作用域 6. 类的实例化 7. 类对象模型 7.1 如何计算类对象的大小 7.2 类对象的存储方式猜测 7.3 结构体内存对齐规则 8. this指针 8.1 this指…

springboot引入第三方jar包放到项目目录中,添加web.xml

参考博客&#xff1a;https://www.cnblogs.com/mask-xiexie/p/16086612.html https://zhuanlan.zhihu.com/p/587605618 1、在resources目录下新建lib文件夹&#xff0c;将jar包放到lib文件夹中 2、修改pom.xml文件 <dependency><groupId>com.lanren312</grou…

rollout

构建 测试 代码扫描 打包 打镜像 推送镜像 部署应用 Rollout 是 Kubernetes 中用于管理部署应用的资源对象。它通过控制多个 ReplicaSets 对象的创建、缩放和更新&#xff0c;以实现无宕机升级和回滚应用程序版本的能力。 一般来说&#xff0c;在 Kubernetes 中&#xff0c;我…

Gem5模拟器学习之旅——翻译自官网

文章目录 安装并使用gem5 模拟器支持的操作系统和环境依赖在 Ubuntu 22.04 启动(gem5 > v21.1)Docker获取代码用 SCons 构建用法首次构建 gem5gem5 二进制类型调试opt快速 常见错误错误的 gcc 版本Python 位于非默认位置未安装 M4 宏处理器Protobuf 3.12.3 问题 安装并使用g…

基于django水果蔬菜生鲜销售系统

基于django水果蔬菜生鲜销售系统 摘要 基于Django的水果蔬菜生鲜销售系统是一种利用Django框架开发的电子商务平台&#xff0c;旨在提供高效、便捷的购物体验&#xff0c;同时支持水果蔬菜生鲜产品的在线销售。该系统整合了用户管理、产品管理、购物车、订单管理等核心功能&…

数据结构初阶leetcodeOJ题(二)

目录 第一题 思路&#xff1a; 第二题 思路 第三题 描述 示例1 思路 总结&#xff1a;这种类似的题&#xff0c;都是用快慢指针&#xff0c;相差一定的距离然后输出慢指针。 第一题 给你一个链表的头节点 head 和一个整数 val &#xff0c;请你删除链表中所有满足 Node.val…

Day34力扣打卡

打卡记录 合并石头的最低成本&#xff08;区间DP&#xff09; 链接 与多边形的三角形问题相同&#xff0c;将大问题化小问题&#xff0c;再用中间节点不断地寻找最值。 class Solution:def mergeStones(self, stones: List[int], k: int) -> int:n len(stones)if (n - 1…

ClickHouse建表优化

1. 数据类型 1.1 时间字段的类型 建表时能用数值型或日期时间型表示的字段就不要用字符串&#xff0c;全String类型在以Hive为中心的数仓建设中常见&#xff0c;但ClickHouse环境不应受此影响。 虽然ClickHouse底层将DateTime存储为时间戳Long类型&#xff0c;但不建议存储Long…

Linux进程——exec族函数、exec族函数与fork函数的配合

exec族函数解析 作用 我们用fork函数创建新进程后&#xff0c;经常会在新进程中调用exec函数去执行另外一个程序。当进程调用exec函数时&#xff0c;该进程被完全替换为新程序。因为调用exec函数并不创建新进程&#xff0c;所以前后进程的ID并没有改变。 功能 在调用进程内部…

Golang起步篇(Windows、Linux、mac三种系统安装配置go环境以及IDE推荐以及入门语法详细释义)

Golang起步篇 Golang起步篇一. 安装Go语言开发环境1. Wondows下搭建Go开发环境(1). 下载SDK工具包(2). 解压下载的压缩包&#xff0c;放到特定的目录下&#xff0c;我一般放在d:/programs下(路径不能有中文或者特殊符号如空格等)(3). 配置环境变量步骤1&#xff1a;先打开环境变…

[ATC复盘] abc329 20231118

[ATC复盘] abc329 20231118 总结A - Spread1. 题目描述2. 思路分析3. 代码实现 B - Next1. 题目描述2. 思路分析-3. 代码实现 C - Count xxx1. 题目描述2. 思路分析3. 代码实现 D - Election Quick Report2. 思路分析3. 代码实现 E - Stamp2. 思路分析3. 代码实现 F - Colored…