线程缓存会同步到主内存
线程缓存会同步到主内存
什么时候从“线程缓存 ->主内存 ”?
-
退出 synchronized 同步块(解锁 unlock)
这是你项目中 PersistTask.add() 方法用到的机制。
规则: 当线程退出一个 synchronized 块时,它必须将该线程工作内存中所有共享变量的最新值刷新回主内存。
目的: 确保下一个拿到锁的线程能看到最新的修改。 -
对 volatile 变量执行写操作
规则: 当线程对一个 volatile 修饰的变量进行赋值时,JVM 会立即将这个新值刷新到主内存。
特点: 即使没有加锁,其他线程也能立刻看到这个变量的变化。 -
线程结束(Thread Termination)
规则: 当一个线程执行完毕(run 方法结束)并死亡时,它会将所有共享变量的值同步回主内存。
场景: 比如你在子线程里算完一个结果,主线程通过 thread.join() 等待子线程结束后,就能拿到最新的结果。 -
调用特定的原子类或并发工具方法
Java 的 java.util.concurrent 包里的很多工具内部都使用了 volatile 或 CAS 操作,它们也会触发同步:
原子类: 如 AtomicInteger.incrementAndGet()。
线程安全容器: 如 ConcurrentHashMap.put()、BlockingQueue.put()。
原理: 这些方法的底层实现通常涉及 volatile 写或 Unsafe 操作,从而保证可见性。 -
显式使用 Unsafe 或 VarHandle
如果你直接使用底层的 Unsafe.storeFence() 等方法,可以强制刷新缓存。但这属于高级用法,普通业务代码很少见。
反向操作:什么时候从“主内存 -> 线程缓存”?
为了保证你能读到别人改过的数据,以下情况会触发读取主内存:
- 进入 synchronized 同步块(加锁 lock)。
- 读取 volatile 变量。
- 线程启动(Thread.start):子线程刚开始运行时,会从主内存拷贝一份父线程修改过的数据。
- 调用 thread.join() 返回后。
总结一张表
| 动作 | 方向 | 触发条件 |
|---|---|---|
| 刷新 (Flush) | 工作内存 -> 主内存 | 1. 解锁 (synchronized 结束) 2. 写 volatile 变量 3. 线程结束 |
| 读取 (Load) | 主内存 -> 工作内存 | 1. 加锁 (synchronized 开始) 2. 读 volatile 变量 3. 线程启动 |
浙公网安备 33010602011771号