volatile学习笔记
三大特性
jmm编程的三大特性
1:可见性
2:原子性
3:有序性
但是volatile对于三大特性却只支持两个(可见性和禁止指令重排),它不不保证原子性
可见性
这个是可见性的理论,以及正常java程序的内存流程,可见性会将修改去及时的通知主内存,让其他的线程也看到
场景:现在有个对象,里面有个成员变量,主线程中开了一个新的线程,新线程和主线程操作同一个对象,但是对象里面值进行改变时,另一个对象是不知道的。将成员变量加上volatile则当某一线程将主内存值改变时,所有线程立刻就会被感知
volatile不保证原子性
假如当成千上万个线程操作成员变量时,因为没原子性,可能读到相同的值后进行不同运算进行写入,但是后面写入就会覆盖原来的。就是因为在其他线程未运算结束时,某线程又拿到原值进行运算以及写入就会导致其他线程的值被覆盖
解决不保证原子性问题
1.可以用synchronized关键字,但是不必要。这个方案不建议。
2.可以用java.util.concurrent下的AtomicInteger,因为它具有原子性(java.util.concurrent里面是个提供原子性的类,其中有AtomicInteger,原子性的integer值。)
禁止指令重排
系统为了代码的性能可能会对指令顺序进行重新排序。也就是说不见得会按照源代码中的编写顺序去执行顺序。所以这就是指令重
下面是指令重排的小结
单例模式的DCl不一定安全(因为指令重排)。看下
上面图片这种高并发情况下,很低几率仍然会出现问题,并不是绝对安全的单例。具体原因看下面
最后的解决方案,将对象变量加上volatile修饰,禁止指令重排