volatile
volatile
是一个关键字,用于声明变量。它的主要作用是告诉编译器,这个变量可能会被多个线程同时访问,因此不应该进行某些优化,而应该确保对这个变量的读写操作在多线程环境下是正确的。volatile
关键字的主要作用包括两点:
- 禁止指令重排序:
volatile
关键字保证了变量的读写操作不会被重排序,这对于某些需要依赖于操作顺序的场景是非常重要的。- 保证可见性:当一个线程修改了一个
volatile
变量的值时,这个新值会立即对其他线程可见,确保了多线程之间对变量的可见性。
原理:
Java
虚拟机(JVM)
中,每个线程都有自己的工作内存,工作内存中保存了变量的副本。当一个线程修改了变量的值时,首先会在自己的工作内存中进行修改,然后将修改后的值刷新到主内存中。而其他线程在读取这个变量的值时,会首先从主内存中读取最新的值到自己的工作内存中,然后再进行操作。
volatile
关键字的作用就是当一个线程修改了volatile
变量的值时,会立即将修改后的值刷新到主内存中,而当其他线程读取这个变量的值时,会直接从主内存中获取最新的值,而不是从自己的工作内存中获取。这就保证了对volatile
变量的读写操作在多线程环境下是正确的。
小试牛刀
public class VolatileTest {
//public volatile int inc = 0;
public int inc = 0;
public void increase() {
inc++;
}
public static void main(String[] args) throws InterruptedException {
final VolatileTest test = new VolatileTest();
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(10,
10,
1000,
TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>(),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy());
for (int i = 0; i < 10; i++) {
threadPoolExecutor.execute(() -> {
for (int j = 0; j < 1000; j++) {
test.increase();
}
});
}
threadPoolExecutor.shutdown();
System.out.println(test.inc); //每次结果都不一样
}
}
结果小于10000
volatile关键字能保证可见性没有错,但是上面的程序错在没能保证原子性。可见性只能保证每次读取的是最新的值,但是volatile没办法保证对变量的操作的原子性。