1.對(duì)線程的可見性
Java的volatile關(guān)鍵字聲明使變量對(duì)不同線程具有可見性。程序在多線程操作non-volatile變量時(shí),為了提升性能,每個(gè)線程會(huì)將變量從主內(nèi)存復(fù)制到CPU緩存。如果有多個(gè)CPU核心,每個(gè)線程可能在不同的CPU上運(yùn)行。這意味著每個(gè)線程的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永遠(yuǎn)等于0,加volatile之后Counter會(huì)發(fā)生變化
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 運(yùn)行結(jié)果:
二月 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 運(yùn)行結(jié)果:
二月 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.對(duì)線程的有序性
volatile可以禁止指令重排序,volatile標(biāo)識(shí)的變量,會(huì)有內(nèi)存屏障,指令重排序時(shí)就不能把后面的指令重排序到內(nèi)存屏障之前的位置,這樣就保證不同的代碼塊只能串行執(zhí)行,不能同步執(zhí)行,這樣就保證了線程的有序性。