Volatile的相关内容
首先补充几个知识点:
内存可见性
举一个例子:
终端:
分析:t2线程没问题,问题在于t1。1!=0,t1应该结束才对。
·t2改了flag,t1没有看见。 t2是写入,t1是读取
·flag变量的修改对于t1线程不可见了
编译器优化
·大多数情况是可以做到逻辑不变并对代码优化调整,提高效率,但一些特定场景可能会出现误判
比如这个过程:load(拿数据--读内存),cmp(比较--寄存器操作),load,cmp 反复执行,在反复执行中拿到flag一样;但是load比cmp耗时多---读内存比读寄存器效率慢得多。此时load读到的值一样,编译器直接把从内存读取flag这个操作优化掉了。
·编译器不是看不见改变,而是不知道另外一个线程的他flag修改代码能不能执行以及啥时候执行。
--用户输入啥,编译器无法预计。
volatile解决内存可见性引起的线程安全问题
关键字修饰变量:
·提醒JVM在读写volatile变量指令前后添加“内存屏障相关的指令“
结合java内存模型 --- JMM
·一个java进程会有一个“主内存”存储空间
·每个java线程又有自己的“工作内存”存储空间---其实不是内存,是存储介质
-再深层一点,在操作系统分析,“工作内存”中不仅有寄存器,还有缓存,(缓存有很多层)
·上方的代码例子,t1进行flag变量的判定,先把flag值从主内存读到工作内存,用工作内存中的值进行判定。同时t2对flag进行修改,修改的是主内存的值,主内存的变更不会影响到t1的工作内存