1. 目的
用Java程式测试一下volatile关键字的作用。
2. 代码
package volatile_;
import java.io.IOException;
public class Volatile {
private static /*volatile*/ boolean running = true;
private static void test() {
System.out.println("test start");
while (running) {
}
System.out.println("test end");
}
public static void main(String[] args) throws InterruptedException, IOException {
new Thread(() -> {
test();
}).start();
Thread.sleep(1000);
running = false;
}
}
未用volatile修饰变量running
解读一下代码,running变量是boolean型用来控制test方法的while循环(虽然里面无任何操作,TRUE即死循环);test方法先输出test start,再判断是否进去while循环,最后输出test end;主函数里有一个新线程去调用这个test方法;main线程会休眠一秒,休眠结束将running变量设为false。
期待结果:当主线程将running变量设为false时,调用test方法的线程应该是退出了while循环。
实际结果:当主线程将running变量设为false时,调用test方法的线程没有退出while循环;test end这句话永远没有输出。
用volatile修饰变量running
期待结果:当主线程将running变量设为false时,调用test方法的线程应该是退出了while循环。
实际结果:当主线程将running变量设为false时,调用test方法的线程退出了while循环;输出了test end这句话。
3. 结论
-
明明running变量在休眠一秒后设置为false, 可是调用test方法的线程拿到的running变量的值依然还是true。
这就说明了调用test方法的线程和主线程main读写running变量的位置是不一致的。线程会保持一份变量副本在缓存中,从这个变量副本读取(至于什么时候同步到主内存中我目前不清楚),这就导致了主内存的变量改变了,线程依然没有读取到新的值。 -
使用volatile修饰变量,就能够强制线程从主存去读取变量值而不是从缓存中。
4. 参考文章
https://jingyan.baidu.com/article/fec4bce23c975ab3608d8b59.html