哪些操作会清除线程本地缓存?解析Java示例中操作的共性
关于Java线程缓存与操作触发内存可见性的问题
示例代码与现象
参考的示例代码如下:
public class VolatileKeyword { private static final Logger LOGGER = Logger.getLogger(VolatileKeyword.class); private static int MY_INT = 0; public static void main(String[] args) { new ChangeListener().start(); new ChangeMaker().start(); } static class ChangeListener extends Thread { @Override public void run() { int local_value = MY_INT; while (local_value < 5) { // (A) if (local_value != MY_INT) { LOGGER.info("Got Change for MY_INT : " + MY_INT); local_value = MY_INT; } } } } static class ChangeMaker extends Thread { @Override public void run() { int local_value = MY_INT; while (MY_INT < 5) { LOGGER.log(Level.INFO, "Incrementing MY_INT to " + (local_value + 1)); MY_INT = ++local_value; try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } } } } }
原程序输出
原程序中ChangeListener线程只会读取本地缓存的MY_INT值,输出如下:
Incrementing MY_INT to 1 Incrementing MY_INT to 2 Incrementing MY_INT to 3 Incrementing MY_INT to 4 Incrementing MY_INT to 5
修改(A)处后的输出
若将// (A)替换为以下任一操作,输出会和MY_INT声明为volatile时一致:
Thread.currentThread().isAlive();Thread.sleep(0)Thread.interrupted();System.out.print("");- 为
ChangeListener添加volatile整数x,将// (A)替换为x += MY_INT
此时输出为:
Incrementing MY_INT to 1 Got Change for MY_INT : 1 Incrementing MY_INT to 2 Got Change for MY_INT : 2 Incrementing MY_INT to 3 Got Change for MY_INT : 3 Incrementing MY_INT to 4 Got Change for MY_INT : 4 Incrementing MY_INT to 5 Got Change for MY_INT : 5
问题
上述操作的共同特性是什么,导致线程缓存被清除?补充说明:最后两个操作明显涉及volatile或同步代码从而触发缓存重置,但其他操作的原因是什么?
解答
这些操作的核心共同点是:它们都会触发Java内存模型(JMM)中的内存屏障(Memory Barrier),强制线程刷新本地缓存,重新从主内存读取共享变量。具体拆解:
Thread.currentThread().isAlive()、Thread.sleep(0)、Thread.interrupted():这类Thread类的方法内部包含线程状态检查或底层同步逻辑,JVM会自动为其插入内存屏障,确保线程对共享变量的读写操作与主内存同步,打破本地缓存的只读优化。System.out.print(""):System.out对应的PrintStream类,所有输出方法都带有synchronized同步块。进入/退出同步块时,JMM会强制线程将本地缓存的修改刷入主内存,同时从主内存重新读取所有共享变量的最新值,相当于隐式触发了内存可见性保证。- 涉及volatile变量的操作:volatile变量的读写本身就会触发内存屏障——写volatile会强制刷本地缓存到主内存,读volatile会强制从主内存读取,同时根据JMM的happen-before规则,volatile操作会带动周围共享变量的内存可见性,因此
MY_INT的读取也会同步到主内存的最新值。
本质上,这些操作都间接触发了内存屏障,让ChangeListener线程能看到ChangeMaker线程修改的MY_INT最新值,行为就和MY_INT被声明为volatile一致。
内容的提问来源于stack exchange,提问作者Dazzling4
相关产品推荐
相关产品推荐

