实验过程
实验程序如下:
public class VolatileTest
{
private static volatile int COUNTER = 0;
public static void main(String[] args)
{
new ChangeListener().start();
new ChangeMaker().start();
}
/**
* 监听 COUNTER, 如果 COUNTER 变化, 输出 COUNTER 的值,
* 直到 COUNTER达到 5.
*/
static class ChangeListener extends Thread
{
@Override
public void run()
{
int threadValue = COUNTER;
while (threadValue < 5)
{
if (threadValue != COUNTER)
{
System.out.println("Got Change for COUNTER : " + COUNTER);
threadValue = COUNTER;
}
}
}
}
/**
* 每隔 500ms COUNTER 自增 1,
* 直到 COUNTER 达到 5.
*/
static class ChangeMaker extends Thread
{
@Override
public void run()
{
int threadValue = COUNTER;
while (COUNTER < 5)
{
System.out.println("Incrementing COUNTER to : " + (threadValue + 1));
COUNTER = ++threadValue;
try
{
Thread.sleep(500);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
}
}
}
程序中定义了一个volatile
修饰的int
变量COUNTER
。然后,定义了两个单独的线程,分别为ChangeListener
和ChangeMaker
ChangeListener
:监听COUNTER
,如果发生变化,输出COUNTER
的值,直到COUNTER
达到\(5\);ChangeMaker
:每隔\(500ms\)COUNTER
自增\(1\),直到COUNTER
达到\(5\)
在main
函数中,分别启动这两个线程,观察程序输出结果:
Incrementing COUNTER to : 1
Got Change for COUNTER : 1
Incrementing COUNTER to : 2
Got Change for COUNTER : 2
Incrementing COUNTER to : 3
Got Change for COUNTER : 3
Incrementing COUNTER to : 4
Got Change for COUNTER : 4
Incrementing COUNTER to : 5
Got Change for COUNTER : 5
Process finished with exit code 0
去掉修饰COUNTER
的volatile
,输出结果:
Incrementing COUNTER to : 1
Incrementing COUNTER to : 2
Incrementing COUNTER to : 3
Incrementing COUNTER to : 4
Incrementing COUNTER to : 5
此时让ChangeListener
在循环中等待5ms
,输出结果:
Incrementing COUNTER to : 1
Got Change for COUNTER : 1
Incrementing COUNTER to : 2
Got Change for COUNTER : 2
Incrementing COUNTER to : 3
Got Change for COUNTER : 3
Incrementing COUNTER to : 4
Got Change for COUNTER : 4
Incrementing COUNTER to : 5
Got Change for COUNTER : 5
Process finished with exit code 0
解释
volatile
关键字会确保我们对变量的读写都同步到主内存里,而不是从 Cache 里面读取。
-
使用
volatile
关键字时,两个线程的输出结果相同; -
去掉
volatile
关键字后,ChangeListener
是一个忙等待的循环,他不断地从线程的Cache
中获取COUNTER
的值,于是,这个线程就没有时间从主内存里面同步更新后的COUNTER
,就会已知卡在COUNTER=0
的循环中; -
让循环等待\(5ms\),让线程有机会把最新的数据从主内存同步到
Cache
中,于是ChangeListener
就能监听到ChangeMaker
对COUNTER
变量的修改。