volatile和可见性 2022-02-15 19:36 > 本文尚未完稿,以后会修改的。 ```java package com.example.demo.core.Volatile; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * @author: HanXu * on 2022/2/15 * Class description: 可见性问题剖析,以及volatile解决 */ public class VisibilityDemo { static boolean flag = false; //在前面加上volatile可以解决可见性问题 // static volatile boolean flag = false; private static final Logger logger = LoggerFactory.getLogger(VisibilityDemo.class); public static void main(String[] args) { //开启一个线程,异步延迟修改flag变量的值 new Thread(() -> { try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } flag = true; logger.debug("flag:{}", flag); }).start(); //再次开启一个线程,异步延迟获取flag的值 new Thread(() -> { try { Thread.sleep(200); } catch (InterruptedException e) { e.printStackTrace(); } logger.debug("flag:{}", flag); }).start(); //执行foo() foo(); } static void foo() { int i = 0; while (!flag) { i++; } logger.debug("已停止,i:{}", i); } } /* 开启一个线程,异步延迟修改flag变量的值: 14:00:55.452 [Thread-0] DEBUG com.example.demo.core.Volatile.VisibilityDemo - flag:true 程序不停 再次开启一个线程,异步延迟获取flag的值 14:02:51.333 [Thread-0] DEBUG com.example.demo.core.Volatile.VisibilityDemo - flag:true 14:02:51.432 [Thread-1] DEBUG com.example.demo.core.Volatile.VisibilityDemo - flag:true 程序不停 我们发现第二个线程在延迟200ms之后执行,也获取到了flag正确的值,所以并不是像网上文章所说:flag的值被更改在CPU缓存中,没有及时更新到主存中,所以其他线程无法获取到flag的值。 因为这里可以看到,其他线程确实获取到了。 */ /* 可见性问题原因:JIT即使编译器发现热点代码,于是将其优化为机器指令,while(!flag)就优化为了while(true) 因为他发现执行了几十万次都是true,所以就优化了,以后只执行机器指令,不会再管flag变量是几了。 解决方案: 1、去掉JIT优化:添加VM参数:-Xint 2、将第一个线程的睡眠时间缩短为1ms,这样while(!flag)就不会执行成热点代码了 3、flag添加volatile修饰,volatile修饰的变量保证可见性和有序性。会告诉JIT编译器,不要优化这个变量的操作。【终极正确方案】 */ ``` --END--
发表评论