java异步线程内存可见性实验

【README】

本文演示了内存可见性的场景,以及解决方法;

相关定义如下(转自java并发编程实战,一本好书,强烈推荐):

  1. 内存可见性一个线程修改了对象状态后, 其他线程可以看到修改后的结果;
  2. 对象发布:使对象能够在当前作用域之外的代码中使用; 
  3. 对象逸出:当某个不应该发布的对象被发布时;

【1】内存可见性问题例子

【1.1】测试用例

public class TestVisibility {public static void main(String[] args) {Robot robot = new Robot();new Thread(()->{try {// 睡眠模拟业务逻辑处理TimeUnit.MILLISECONDS.sleep(1000);} catch (InterruptedException e) {}robot.init();}).start();System.out.println(robot.getAge());int count = 0;while(robot.getAge() == 0) {++count;}System.out.println("主线程【成功】读取子线程设置的age值");}
}
/*** @description 机器人* @author xiao tang* @date 2022/2/13*/
class Robot {int age = 0;public void init() {this.age = 10;}public int getAge() {return this.age;}
}

打印结果:

0

while进入了死循环

【1.2】 分析

子线程睡眠一秒,使得主线程可以先从主存(内存)读取到age的值,并放入自己的缓存;

然后子线程再更新age的值并同步到主存;

由于主线程不从主存读取age,所以它使用的是age的失效值(脏数据);


【2】解决方法

1)方法1, 为 Robot.age 添加 volative 修饰符; 以保证age的内存可见性;

2)方法2,为 getAge() 方法 添加 synchronized 修饰符,以保证age的内存可见性;

3)方法3,while循环体,即++count下面添加一条 打印语句,如下:

while(robot.getAge() == 0) {++count;System.out.println(count);}

为什么添加 System.out.println(count); 后就可以解决内存可见性问题了?

因为 pringln 内部是 synchronized 代码块来实现的;如下:

public void println(int x) {synchronized (this) {print(x);newLine();}}

方法3与方法2的原理一样,借助 synchronized 能够保证内存可见性的原理; 


【3】补充

1,对于睡眠语句, TimeUnit.MILLISECONDS.sleep(1000); 我们可以测试出 内存可见性效果;

但是,如果把 1000 换为 1 或 10, 500, ...... 会产生不同的效果,这就类似于不同业务逻辑有着不同的耗时; 即 内存可见性问题会因为不同的耗时而表现出不同的结果

这就很麻烦了,因为如果业务逻辑真正存在可见性问题,但可能没有测试出来,但生产上又存在发生可能性;

我们唯一需要做的就是,在多线程编程时,保证内存可见性,安全的发布共享对象;


【3.1】 happers-before

以下内容转自 :

关于Java内存可见性的探究实验遇到的意外和happens-before - 简书

happens-before字面翻译过来就是先行发生,A happens-before B 就是A先行发生于B?

不准确!在Java内存模型中,happens-before
应该翻译成:前一个操作的结果可以被后续的操作获取。讲白点就是前面一个操作把变量a赋值为1,那后面一个操作肯定能知道a已经变成了1。

我们再来看看为什么需要这几条规则?

因为我们现在电脑都是多CPU,并且都有缓存,导致多线程直接的可见性问题。

所以为了解决多线程的可见性问题,就搞出了happens-before原则,让线程之间遵守这些原则。编译器还会优化我们的语句,所以等于是给了编译器优化的约束。不能让它优化的不知道东南西北了!。

1)关于 happens-before,有以下8条规则:

  1. 单线程Happens-Before原则:在同一个线程中,书写在前面的操作happen-before后面的操作。
  2. 锁的Happens-Before原则:同一个锁的unlock操作happen-before此锁的lock操作。(本文中的 System.out.println中的 synchronized 就是java内置锁
  3. volatile的Happens-Before原则:对一个volatile变量的写操作happen-before对此变量的任意操作(当然也包括写操作了)。
  4. Happens-Before的传递性原则:如果A操作 happen-before B操作,B操作happen-before C操作,那么A操作happen-before C操作。
  5. 线程启动的Happens-Before原则:同一个线程的start方法happen-before此线程的其它方法。
  6. 线程中断的Happens-Before原则:对线程interrupt方法的调用happen-before被中断线程的检测到中断发送的代码。
  7. 线程终结的Happens-Before原则:线程中的所有操作都happen-before线程的终止检测。
  8. 对象创建的Happens-Before原则:一个对象的初始化完成先于他的finalize方法调用。

详细请看:https://segmentfault.com/a/1190000011458941

2)本文中锁的happens-before的作用:

由于happens-before原则,在获取锁时,主线程会使自己CPU的缓存失效,重新从主内存中读取变量的值。这样,子线程中的操作结果就会被主线程感知到了,从主内存中获取了最新的a值。

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

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

相关文章

springboot 单例_如何实现一个单例及优化

前言 社长,一个爱学习,爱分享的程序猿,始终相信,付出总会有回报的。 知识改变命运,学习成就未来。爱拼才会赢! 程序猿学社的GitHub,已整理成相关技术专刊,欢迎 Star:。 https:// github.com/ITfqyd/cxyxs 社长,4年api搬运工程师,之前做的都是一些框架的搬运工作,做的时间…

乐观锁的一种实现方式——CAS

转载自 乐观锁的一种实现方式——CAS在深入理解乐观锁与悲观锁一文中我们介绍过锁。本文在这篇文章的基础上,深入分析一下乐观锁的实现机制,介绍什么是CAS、CAS的应用以及CAS存在的问题等。线程安全 众所周知,Java是多线程的。但是&#xff0…

熬夜并不值得程序员炫耀

许多程序嘴上经常挂着每天加班到凌晨三点的论调,但事实上这没什么值得炫耀的,加班通常都是效率低的代名词。 放弃睡眠就像是高利贷借款。没错,看上去你是得到了额外的时间,但你想得太乐观了,你知道代价是什么吗&#x…

前端wxml取后台js变量值_这些鲜为人知的前端冷知识,你都GET了吗?

背景最近公司项目不多,比较清闲,划水摸鱼混迹于各大技术博客平台,瞬间又GET了好多前端技能,一些属于技巧,一些则是闻所未闻的冷知识,一时间还消化不过来,不由的发出一声感叹!前端可真…

(转-这篇文章非常棒) Thread的中断机制(interrupt)

转自: Thread的中断机制(interrupt)-这篇文章非常棒 Thread的中断机制(interrupt) - 寂静沙滩 - 博客园先看收集了别人的文章,全面的了解下java的中断:中断线程线程的thread.interrupt()方法是中断线程,将会设置该线程的中断状态…

深入理解乐观锁与悲观锁

转载自 [初级]深入理解乐观锁与悲观锁在数据库的锁机制中介绍过,数据库管理系统(DBMS)中的并发控制的任务是确保在多个事务同时存取数据库中同一数据时不破坏事务的隔离性和统一性以及数据库的统一性。 乐观并发控制(乐观锁)和悲观并发控制&a…

Z.ExtensionMethods 一个强大的开源扩展库

今天有意的在博客园里面搜索了一下 Z.ExtensionMethods 这个扩展类库,确发现只搜到跟这个真正相关的才两篇博文而已,我都点进去看了一下,也都只是提到而已,没有专门介绍,才引起我写这篇文档。 一. Z.E…

python isodd奇偶_Python这些位运算的妙用,绝对让你大开眼界

位运算的性能大家想必是清楚的,效率绝对高。相信爱好源码的同学,在学习阅读源码的过程中会发现不少源码使用了位运算。但是为啥在实际编程过程中应用少呢?想必最大的原因,是较为难懂。不过,在面试的过程中,…

java线程中断

【README】 本文po出了不同场景下线程中断的不同开发方式,包括阻塞,非阻塞,io阻塞线程等; 本文部分内容转自:这篇博文写的非常好 Thread的中断机制(interrupt) - 寂静沙滩 - 博客园先看收集了别人的文章&#xff0c…

WEB API系列(一):WEB API的适用场景、第一个实例

在我前一篇博客《WebAPI前置知识:HTTP与RestfulAPI》中已经给各位简单介绍了HTTP协议与RestFul API的关系,以及一些基本的HTTP协议知识,在这些知识的铺垫下,今天,我们一起来讨论一下WEB API的适用场景,然后写我们第一个…

rpa文件怎么提取内容_怎么编辑pdf文件内容?有什么软件可以编辑pdf文件吗?

怎么编辑pdf文件内容?我是2020年大学新生,选择学习的专业是财务管理。为了更快、更深入地了解更多专业知识,我上网查找、下载了很多相关资料。不过,从网上保存下来的资料文件大多是pdf格式的,想要编辑它还得先转word。…

Future取消线程执行

【README】 本文总结于 《java并发编程实战》 page121,非常棒的一本书; 【1】Future 1,介绍:future 用于管理任务的生命周期,处理异常,以及实现取消; 2,future.cancel() 取消方法…

Nancy之结合tinyfox给我们的应用提供简单的数据服务

说到提供数据服务给我们的一些应用,估计用的最多的也就是json和xml这两种数据格式 实现的方法也是多种多样,web api,mvc的jsonresult和contentresult...等等 本文是结合Nancy、TInyFox、Owin等来实现的 一、前提工作 新建一个空的web应用程序 添加相应的…

javaweb调用python算法_请教怎么用java远程调用python? 多谢

请问如何用java远程调用python? 谢谢!本帖最后由 blackkettle 于 2015-05-07 13:00:41 编辑比如有一台机器 A上安装了python, 另一台机器B要用java 调用A 上的python的某个函数,输入数据在B机器上,所有的计算在A机器完成,结果返回…

(转)如何查看java本地方法

在线查看本地代码, refer2 http://hg.openjdk.java.net/jdk8/jdk8/hotspot/file/tip/src/os/linux/vm/os_linux.cpp 我们知道在java中查看java源码时看到native方法在java层面上就到头的,如果还想继续往下看就需要看jdk是如何实现的,今天就分…

统一配置中心的设计方案

转载自 统一配置中心的设计方案对于配置文件,我们不陌生,它提供我们可以动态修改程序运行能力。引用别人的一句话就是:系统运行时(runtime)飞行姿态的动态调整。我可以把我们的工作称之为在快速飞行的飞机上修理零件。我们人类总是无法掌控和…

微软CEO纳德拉恢弘计划:让开发者始终忘不了微软

BI中文站 4月11日 报道 当微软前CEO史蒂夫•鲍尔默(Steve Ballmer)在2000年喊出“开发者,开发者,开发者”的口号时,他可能有点儿激动,但是他的观点是对的。 30年前当Windows 1.0推出的时候,这种…

python scratch unity_Unity3D研究院之2D游戏开发制作原理(二十一)

经过了4个月不懈的努力,我和图灵教育合作的这本3D游戏开发书预计下个月就要出版了。这里MOMO先打一下广告,图灵的出版社编辑成员都非常给力,尤其是编辑小花为这本书付出了很大的努力,还有杨海玲老师,不然我也无法完成这…

原码补码与反码

【README】 1.本文内容总结自“哈工大刘宏伟”老师的mooc视频《计算机组成原理》on bilibili; 2.为了便于理解,本文引入了逗号分割符号部分和数值部分,计算机存储数据的时候没有逗号; 【1】原码表示法 原码定义: 原…

第一篇 Entity Framework Plus 之 Audit

一般系统会有登陆日志,操作日志,异常日志,已经满足大部分的需求了。但是有时候,还是需要Audit 审计日志,审计日志,主要针对数据增,改,删操作数据变化的记录,主要是对数据…