关于Valotile的理解
2018-03-27 本文已影响0人
猴哥一一
转自小端有话说;
[toc]
请你说下对Valotile的了解,以及使用场景 ?
分析:说到valotile, 我们应该知道它的使用场景是多线程. 对于多线程编程,我们要解决的问题集中在三个方面:
- a.原子性,最简单的例子就是,i++,在多线程环境下,最终的结果是不确定的,为什么?就是因为这么一个++操作,被编译为指令后,是多个指令来完成的。那么遇到并发的情况,就会导致彼此“覆盖”的情况。
- b.可见性,通俗解释就是,在A线程对一个变量做了修改,在B线程中,能正确的读取到修改后的结果。究其原理,是cpu不是直接和系统内存通信,而是把变量读取到L1,L2等内部的缓存中,也叫作私有的数据工作栈。修改也是在内部缓存中,但是何时同步到系统内存是不能确定的,有了这个时间差,在并发的时候,就可能会导致,读到的值,不是最新值。
- c.有序性:这里只说指令重排序,虚拟机在把代码编译为指令后执行,出于优化的目的,在保证结果不变的情况下,可能会调整指令的执行顺序。
valotile,能满足上述的可见性和有序性。但是无法保证原子性
可见性,是在修改后,强制把对变量的修改同步到系统内存。而其他cpu在读取自己的内部缓存中的值的时候,发现是valotile修饰的,会把内部缓存中的值,置为无效,然后从系统内存读取。
有序性,是通过内存屏障来实现的。所谓的内存屏障,可以理解为,在某些指令中,插入屏障指令,用以确保,在向屏障指令后面继续执行的时候,其前面的所有指令已经执行完毕。
既然说valotile 还无法保证线程安全, 那该如何线程安全 ?
这时候就需要同步器比如 synchronized 的介入, 来保证原子性了;
毕竟 原子性 + 可见性 + 有序性
才能保证线程安全
valotile在单例模式中的应用
在写单例模式时,我们通常会采用双层判断的方式,在最内层,instance = new Singleton()。其实这也有一个隐含的问题:这句赋值语句,其实是分三步来操作的:
a.为instance分配内存
b.调用Singleto构造函数来初始化变量
c.instance指向上一步初始化的对象
在jvm做了指令重排序优化后,上述步骤b和c不能保证,可能出现,c先执行,但是对象却没初始化,这时候其他线程判断的时候,发现是非null,但是使用的时候,却没有具体实例,导致报错。
所以,我们可以用valotile来修饰instance,避免该问题。