概述
volatile是Java的一个修饰符,它在多线程编程开发中保证了共享变量的可见性和有序性。相对于各种排他锁,volatile在使用和执行成本上占用资源较少。
实现原理
那么volatile如何保证可见性和有序性呢?我们写一段单例模式的java代码:
1 | package com.test; |
然后用idea运行main方法并打印汇编代码,jvm参数:
-server -Xcomp -XX:+UnlockDiagnosticVMOptions -XX:+PrintAssembly
-XX:CompileCommand=compileonly,*SingletonObject.get (只打印SingletonObject的get方法)
运行打印结果:
1 | # {method} {0x0000000128e022b0} 'get' '()Lcom/test/SingletonObject;' in 'com/test/SingletonObject' |
我们可以看到被volatile修饰的共享变量进行写操作的时候,会比普通公共变量的读写操作多一行lock addl $0x0,(%rsp)前缀的代码,lock前缀指令有俩个作用:
- 使用总线锁或缓存一致性协议来保证数据的可见性。
- 不是内存屏障却能完成类似内存屏障的功能,阻止屏障两遍的指令重排序保证有序性。
总结
volatile的使用场景不是很多,常用在多线程下的状态标记量和双重检查等,也有很多地方配合CAS来实现无锁编程。因为volatile只能保证线程每次拿到的数据是最新的,对于数据的单纯查询没有任何问题(jvm自动保证基本数据类型和引用的取值赋值为原子操作,lock指令保证有序性和可见性),但是对于i++、懒汉式单例模式等对变量操作依赖当前值的情况,就显得无能为力。