大家好,又见面了,我是你们的朋友全栈君。
如何通知其他线程的工作内存(缓存)失效
嗅探机制工作原理:每个处理器通过监听在总线上传播的数据来检查自己的缓存值是不是过期了,如果处理器发现自己缓存行对应的内存地址修改,就会将当前处理器的缓存行设置无效状态,当处理器对这个数据进行修改操作的时候,会重新从主内存中把数据读到处理器缓存中。
注意:基于 CPU 缓存一致性协议,JVM 实现了 volatile 的可见性,但由于总线嗅探机制,会不断的监听总线,如果大量使用 volatile 会引起总线风暴。所以,volatile 的使用要适合具体场景。
voliate的lock指令其实就相当于加了内存屏障,使用了volatile修饰变量,则对变量的写操作,会插入StoreLoad屏障。
上述内存屏障的插入策略是非常保守的,比如一个volatile的写操作前后需要加上StoreStore和StoreLoad屏障,但这个写volatile后面可能并没有读操作,因此理论上只加上StoreStore屏障就可以,的确,有的处理器就是这么做的。但JMM这种保守的内存屏障插入策略能够保证在任意的处理器平台,volatile变量都是有序的。
首先说明i++的操作本身就不是原子性的,而是分为三步
1、线程读取i 2、i自增,temp = i + 1 3、刷回主存,i = temp
举例说明: 1)当 i=5 的时候A,B两个线程同时读入了 i 的值, 2)然后A线程执行了 temp = i + 1的操作, 要注意,此时的 i 的值还没有变化, 3)此时B线程也执行了 temp = i + 1的操作,注意,此时A,B两个线程保存的 i 的值都是5,temp 的值都是6, 4)然后A线程执行了 i = temp (6)的操作,此时i的值会立即刷新到主存并通知其他线程保存的 i 值失效, 5)此时B线程需要重新读取 i 的值那么此时B线程保存的 i 就是6,同时B线程保存的 temp 还仍然是6, 然后B线程执行 i=temp (6),所以导致了计算结果比预期少了1
也就是说B线程在自增之后(temp = 6),刷回主存之前,重新获取获取到了当前主存中最新的变量值6,但是此时自增操作已经完成了,这时候再重新将temp=6刷回主存,相当于B没有进行自增。
总之,其实voliate对变量的读写是线程安全的,但是变量的操作却不是线程安全的。
参考博客:https://www.jianshu.com/p/d7f78ac13c6a
发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/142784.html原文链接:https://javaforall.cn