靖江网站建设价格,微擎应用市场,丁香花影视大全,百度学术论文查重官网入口【README】
本文演示了内存可见性的场景#xff0c;以及解决方法#xff1b;
相关定义如下#xff08;转自java并发编程实战#xff0c;一本好书#xff0c;强烈推荐#xff09;#xff1a;
内存可见性#xff1a;一个线程修改了对象状态后#xff0c; 其他线程可以…【README】
本文演示了内存可见性的场景以及解决方法
相关定义如下转自java并发编程实战一本好书强烈推荐
内存可见性一个线程修改了对象状态后 其他线程可以看到修改后的结果对象发布使对象能够在当前作用域之外的代码中使用 对象逸出当某个不应该发布的对象被发布时【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方法3while循环体即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条规则
单线程Happens-Before原则在同一个线程中书写在前面的操作happen-before后面的操作。锁的Happens-Before原则同一个锁的unlock操作happen-before此锁的lock操作。本文中的 System.out.println中的 synchronized 就是java内置锁volatile的Happens-Before原则对一个volatile变量的写操作happen-before对此变量的任意操作(当然也包括写操作了)。Happens-Before的传递性原则如果A操作 happen-before B操作B操作happen-before C操作那么A操作happen-before C操作。线程启动的Happens-Before原则同一个线程的start方法happen-before此线程的其它方法。线程中断的Happens-Before原则对线程interrupt方法的调用happen-before被中断线程的检测到中断发送的代码。线程终结的Happens-Before原则线程中的所有操作都happen-before线程的终止检测。对象创建的Happens-Before原则一个对象的初始化完成先于他的finalize方法调用。
详细请看https://segmentfault.com/a/1190000011458941
2本文中锁的happens-before的作用 由于happens-before原则在获取锁时主线程会使自己CPU的缓存失效重新从主内存中读取变量的值。这样子线程中的操作结果就会被主线程感知到了从主内存中获取了最新的a值。