public class VolatileTest {
private static boolean stop = false;
public static void main(String[] args) {
Thread thread = new Thread(() -> {
System.out.println("start");
long i = 0;
System.out.println("i:" + i);
while (!stop){
i++;
}
System.out.println("stop;i:" + i);
}, "volatileTestThread");
thread.start();
System.out.println("set stop start");
stop = true;
System.out.println("set stop end");
}
}
结果:
set stop start
set stop end
start
i:0
stop;i:0
volatileTestThread还没有开始,main线程就执行到stop = true了,所以加上main线程休眠继续测试。
public class VolatileTest {
private static boolean stop = false;
public static void main(String[] args) {
Thread thread = new Thread(() -> {
System.out.println("start");
long i = 0;
System.out.println("i:" + i);
while (!stop){
i++;
}
System.out.println("stop;i:" + i);
}, "volatileTestThread");
thread.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("set stop start");
stop = true;
System.out.println("set stop end");
}
}
结果:
start
i:0
set stop start
set stop end
如果stop没有volatile修饰,volatileTestThread不会终止。stop加上volatile修饰继续测试。
public class VolatileTest {
private static volatile boolean stop = false;
public static void main(String[] args) {
Thread thread = new Thread(() -> {
System.out.println("start");
long i = 0;
System.out.println("i:" + i);
while (!stop){
i++;
}
System.out.println("stop;i:" + i);
}, "volatileTestThread");
thread.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("set stop start");
stop = true;
System.out.println("set stop end");
}
}
结果:
start
i:0
set stop start
set stop end
stop;i:-1320028603
volatile保证了线程volatileTestThread对stop的可见性。
示例中while循环被终止了。i最终为负值,是因为i曾经加到Integer.MAX_VALUE,再加1就会成为最小值(-2147483648),然后继续加,还没加到0就stop为true退出循环了。请看示例:
int ii = Integer.MAX_VALUE;
// 2147483647
System.out.println(ii);
ii++;
// -2147483648
System.out.println(ii);
// true
System.out.println(ii == Integer.MIN_VALUE);
// -2147483647
ii++;
System.out.println(ii);
扩展一下(即使不加volatile也能终止volatileTestThread的多种方式):
(1)启动参数(VM options)设置-Djava.compiler=NONE,关闭JIT编译器。
(2)循环体中有释放锁的操作,同步主内存。比如:
while (!stop){
i++;
// println里面有同步代码块
System.out.println(i);
}
或:
while (!stop){
i++;
// 同步代码块
synchronized (VolatileTest.class){
}
}
(3)循环体中有IO操作:
while (!stop) {
i++;
new File("test.txt");
}
(4)循环体中线程sleep或者yield,CPU时间片切换:
while (!stop) {
i++;
try {
Thread.sleep(0);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
while (!stop) {
i++;
Thread.yield();
}
(5)循环体中的i被volatile修饰:
public class VolatileTest {
private static boolean stop = false;
private static volatile int i = 0;
public static void main(String[] args) {
Thread thread = new Thread(() -> {
System.out.println("start");
while (!stop) {
i++;
}
System.out.println("stop;i:" + i);
}, "volatileTestThread");
thread.start();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("set stop start");
stop = true;
System.out.println("set stop end");
}
}