volatile关键字,是Java面试中避免不了的一个问题,我们来好好的剖析一下这个JUC的关键字。
volatile 是Java提供的一个轻量级同步机制。它保证了内存的可见性,不保证原子性,禁止指令重排序。我们用实际代码来分析这三个方面,分析完之后你就知道了为什么volatile是一个轻量级的同步机制了。
- 可见性
由JMM内存模型可以知道,线程拥有自己的工作内存,该工作内存由自己独享,其他线程访问不了。线程在进行读写操作时,要从主内存中拷贝一份数据放入自己的工作内存中,然后在自己的工作内存中进行读写操作,操作完后,再放回主内存。可见性就是如果一个变量被更新完放入主内存后,他会通知其他的线程,然后其他线程就会从主内存中拷贝最新的数据进自己的工作内存。理论就这么多,用两个例子来证明可见性。
import java.util.concurrent.TimeUnit;
public class Test {
public static void main(String[] args) {
Data data = new Data();
/*
我们在这里新建一个线程,这个线程调用了Data类的方法,修改了number的值,但是主线程Main发现不了
*/
new Thread(()->{
System.out.println(Thread.currentThread().getName() + " come in " +data.number);
try {
TimeUnit.SECONDS.sleep(3);
} catch (InterruptedException e) {
e.printStackTrace();
}
data.change();
System.out.println(Thread.currentThread().getName() + " 修改已经完成~ " + data.number);
},"A").start();
while (data.number == 0){
}
System.out.println("已检测到number值发生变化~");
}
}
/*
资源类
*/
class Data {
int number = 0;
public void change() {
number = 5;
}
}
程序的运行结果可想而知,主线程一直在while中出不去,因为它没有更新number的值。

我们加上volatile后试试
class Data {
volatile int number = 0;
public void change() {
number = 5;
}
}

加上volatile之后,Main线程会被通知number的更新操作,所以看到这里相信你应该了解了volatile的保证可见性了。
- 不保证原子性
那么什么是原子性?原子性就是不可再分且不可简化,要么全部成功 ,要么全部失败。原子操作就是一旦这个操作开始之后,直到这个操作完成,都不能中断这个操作。
public class Test {
public static void main(String[] args) {
Data data = new Data();
/*
创建20个线程,让每个线程调用1000次add方法,如果保证原子性的话,答案是20000
*/
for (int i = 1; i <= 20; i++) {
new Thread(()->{
for (int j = 1; j <= 1000; j++) {
data.add();
}
}).start();
}
/* 阻塞Main线程直到每个线程都完成计算任务后
因为程序中本身就有Main线程和GC线程,如果线程数大于2,证明还有线程没计算完
*/
while (Thread.activeCount() > 2) {
Thread.yield();
}
System.out.println(data.number);
}
}
class Data {
volatile int number = 0;
public void add() {
number++;
}
}
程序运行结果并没有出乎意料,



由此可以证明volatile不保证原子性
- 禁止指令重排序
指令重排序是操作系统对程序编译的优化,在单线程程序下,指令重排序之后的结果不会改变,但是在多线程环境下,不能保证数据的一致性,volatile能禁止指令重排序
网友评论