Volatile关键字
volatile是一种轻量级的同步机制,不会对变量加锁,也不会阻塞线程。
volatile与synchronize的区别
synchronize可以保证可见性和原子性,volatile无法保证原子性;
性能上的比较:Java虚拟机对锁实行了许多消除和优化,很难量化二者的性能差别;
Volatile可以保证内存可见性
用volatile关键字修饰的变量,虽然也会从主内存中保存一份变量副本到工作内存中,但是volatile规定线程直接操作主存中的变量,当有线程要读取该变量时,volatile强制变量同步到主内存中,保证变量的数据一致性。所以可见性的意思是当一个线程修改了变量的值时,其他线程都能从主存中读取到该变量的新值。(普通变量保证可见性:当线程A修改普通变量的值,然后同步回主存中,线程B必须在线程A完成可同步操作后再读取普通变量的值,新值才能对线程B可见)
Volatile不能保证原子操作
Volatile能保证线程可见性,但并不能保证并发下的线程安全。因为Java运算的非原子性操作导致volatile修饰的变量在并发下不是安全的。比如说自增运算i++,运算分为三步操作,读取、自增、写入,volatile只能保证在第一步读取时数据是安全的,但是在并发下后面两步操作是非线程安全的。由于volatile只能保证内存可见性,无法保证原子性,所以如果不符合以下两种运算场景的话,仍然要通过加锁来保证线程安全:
(1)变量的运算结果并不依赖于当前值,或者只有单一线程修改变量值的情况下;
(2)变量不需要与其他线程共享数据;
Volatile可以禁止指令重排序
Java虚拟机为了保证充分利用CPU资源,可能会对代码执行顺序打乱,计算完之后再把结果重组,保证计算的结果与顺序执行的结果是一致的,但是并不能保证程序计算的顺序与程序代码顺序一致。当在并发条件下,会导致有些代码片段先被执行了,导致结果不一致的情况。Volatile的禁止指令重排序可以防止这种情况发生(DCL的单例模式使用volatile就是利用其禁止指令重排序的特性来保证线程安全的)。
Volatile的性能
Volatile变量读操作的性能消耗与普通变量几乎没有差别,但是写操作可能会慢一些,因为需要在本地代码中插入许多内存屏障指令来保证处理器不乱序执行。
网友评论