1.对线程的可见性
Java的volatile关键字声明使变量对不同线程具有可见性。程序在多线程操作non-volatile变量时,为了提升性能,每个线程会将变量从主内存复制到CPU缓存。如果有多个CPU核心,每个线程可能在不同的CPU上运行。这意味着每个线程的CPU缓存的变量的值可能不一样。如图所示:

import java.util.concurrent.TimeUnit;
import java.util.logging.Logger;
public class VolatileTest {
private static Logger logger = Logger.getLogger(VolatileTest.class.getName());
private static volatile int Counter = 0;
public static void main(String[] args) {
new ChangeListener().start();
new ChangeMaker().start();
}
static class ChangeListener extends Thread {
@Override
public void run() {
int localValue = Counter;
while (localValue < 2) {
//不加volatile Counter永远等于0,加volatile之后Counter会发生变化
if (localValue != Counter) {
logger.info(Thread.currentThread().getName() + " 值被修改了 Counter = " + Counter);
localValue = Counter;
}
}
}
}
static class ChangeMaker extends Thread {
@Override
public void run() {
int localValue = Counter;
while (Counter < 2) {
logger.info(Thread.currentThread().getName() + " Counter+1 = " + (localValue + 1));
Counter = ++localValue;
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
}
不加volatile 运行结果:
二月 22, 2019 12:06:56 上午 VolatileTest$ChangeMaker run
信息: Thread-2 Counter+1 = 1
二月 22, 2019 12:06:57 上午 VolatileTest$ChangeMaker run
信息: Thread-2 Counter+1 = 2
加了volatile 运行结果:
二月 22, 2019 12:05:30 上午 VolatileTest$ChangeMaker run
信息: Thread-2 Counter+1 = 1
二月 22, 2019 12:05:30 上午 VolatileTest$ChangeListener run
信息: Thread-1 值被修改了 Counter = 1
二月 22, 2019 12:05:31 上午 VolatileTest$ChangeMaker run
信息: Thread-2 Counter+1 = 2
二月 22, 2019 12:05:31 上午 VolatileTest$ChangeListener run
信息: Thread-1 值被修改了 Counter = 2
2.对线程的有序性
volatile可以禁止指令重排序,volatile标识的变量,会有内存屏障,指令重排序时就不能把后面的指令重排序到内存屏障之前的位置,这样就保证不同的代码块只能串行执行,不能同步执行,这样就保证了线程的有序性。
网友评论