对于Java中volatle型变量的介绍,《深入理解Java虚拟机-JVM高级特性与最佳实践(周志明 著)》介绍的比较全面和易懂,当一个变量定义为volatile之后,将具备一种特性是保证此变量对所有线程的可见性,这里的“可见性”是指当一条线程修改了这个变量的值,新值对于其他线程来说是可以立即得知的,而普通变量不能做到这一点,普通变量的值在线程间传递均需要通过主内存来完成,例如,线程A修改一个普通变量的值,然后向主内存进行回写,另外一条线程B在线程A回写完成了之后再从主内存进行读取操作,先变量值才会对线程B可见。volatile变量虽然对所有线程是立即可见的,但是基于volatile变量的运算在并发下是不安全的,因为Java里面的运算并非原子操作,导致volatile变量的运算在并发下一样是不安全。对于普通变量想达到马上可见需要使用synchronized。
并举了下面的例子。
public class VolatileTest {
public static volatile int race = 0;
public static void increase() {
race++;
}
private static final int THREADS_COUNT = 20;
private static final int INCREASE_COUNT = 10000;
public static void main (String[] args) {
Thread[] threads = new Thread[THREADS_COUNT];
System.out.println(System.currentTimeMillis());
for (int i = 0; i < THREADS_COUNT; i++) {
threads[i] = new Thread(new Runnable() {
@Override
public void run () {
for (int i = 0; i < INCREASE_COUNT; i++) {
increase();
}
}
});
threads[i].start();
}
while (Thread.activeCount() > 1) {
Thread.yield();
}
System.out.println(System.currentTimeMillis());
System.out.println(race);
}
}
这段代码发起了20个线程,每个线程对race变量进行10000次自增操作,如果这段代码能够正确并发的话,最终输出的结果应该是200000。我使用JDK的版本是"1.8.0_222",运行环境是"1.8.0_222-8u222-b10-1ubuntu1