volatile关键字要用好很难,但是在某些场景下,volatile变量是线程安全的,并且开销比synchronized关键字要低。
基础知识
锁的两大特性”互斥” 与 “可见性”。 互斥是说,每次都得等先拿到锁的线程把锁释放了,其他线程才有资格访问共享资源,期间线程对共享资源是独占的。而可见性是指,一个线程修改了某个共享变量的值,其他线程能读取到最新的值,而不至于读取到脏数据。
CPU有自己的高速缓存。 CPU执行指令的速度是相当快的,如果每次获取数据时,都需要从操作系统的内存中获取的话,会影响指令的执行速度的。因此CPU会把从内存读取到的数据缓存起来,之后都直接从缓存中获取数据,等数据处理完后,再更新到操作系统的内存中。
注意:
CPU何时把缓存中的数据刷新到内存中是不确定的。
volatile变量特性
volatile变量拥有”可见性”的特性。 也即是说,线程可以看到volatile变量的最新值,而不会看到修改前的值或者不正确的值。这个特性在某些场景下,可以让volatile变量是线程安全的。
volatile变量不具备”原子性”。 举个例子,volatile变量i,进行i++操作时,是不能保证i++操作的原子性的,在多线程并发的情况下,仍然可能有线程安全问题。这个也是volatile必须小心谨慎使用的原因。
硬件层面上支持volatile
当对volatile变量进行写操作的时候,会有一条lock的汇编指令,该指令在多核CPU处理中,会引发出另外两个事情:
1、将CPU缓存中的数据立刻写到操作系统内存中;
2、其他CPU的内部缓存,如果缓存了该共享变量,则直接失效过期。都必须直接去内存中读取正确的值。
volatile性能
跟synchronized不同,volatile不会引起线程挂起,导致线程上下文切换和调度的开销。
volatile使用条件
对变量的写操作不依赖于当前值。反过来说,如果某个操作得先判断当前值是什么值才能进行操作的,则使用volatile不能保证线程安全的。
volatile使用场景
boolean值开关控制
程序中,有时候需要一个开关(true/false)来控制是否做某些事情,可以把开关变量使用volatile来修饰。
参考文章