volatile是基于缓存一致性协议的保证多线程下的有序性和可见性的关键字(修饰类成员变量和类静态成员变量),volatile在JMM的主内存和工作内存之间加了一个MESI(修改,锁定,无效,共享四种状态)
可见性:通过volatile修饰的成员变量在并发下,值被修改其它线程被通知把工作内存的值设为无效状态,重新读主内存的值并运算
有序性:volatile变量,禁止指令的重排,在JVM不经过优化,在程序的前后代码有序执行
可见性演示:
注:线程的可见性问题只有在高并发下的小概率事件,在cpu的高速读载中,线程读写快,并不会发生可见性问题(所有有些情况不加volatile也看起来没问题)
http://wql.luoqin.ltd/wp-content/uploads/2020/05/1.1.png
MESI:
MESI的四种操作:
1,修改:线程通知协议我要修改值
2,失效:线程发出修改指令,MESI将其他线程的值改为无效
3,锁定(排它性):在一个线程没有修改完成时,其他线程不允许操作
4,共享:线程修改完成后,MESI通知其他线程值一更新,其他线程读取新值
http://wql.luoqin.ltd/wp-content/uploads/2020/05/MESI.png
问题:MESI并不能保证原子性,在线程高并发下,一个线程在发出修改时,另一个线程已经将数据交给了执行引擎之后就有了两次共享,MESI不能阻止这一步操作(所有基于MESI的volatile也不能保证原子性)
http://wql.luoqin.ltd/wp-content/uploads/2020/05/MESI1.png
y的值不会到达100,无法保证原子性
2指令重排
指令重排是引发有序性问题的根本所在
指令重排是JVM的优化机制,为优化程序效率一些代码会被优先执行(程序计数器中),从而有些会错乱 ,所有一些要刻意避免重排
避免重排的方法:
1.加volatile关键字(原因:volatile基于MESI,有内存屏障问题,禁止重排)
2,加锁如synchronized锁和Lock锁(原因:jvm中单机模式下必须保证有序性,在锁中每个线程在执行都是是串行的,as-if-serial 语义把单线程程序保护了起来)
Comments | NOTHING
Warning: Undefined variable $return_smiles in /www/wwwroot/wql_luoqin_ltd/wp-content/themes/Sakura/functions.php on line 1109