欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 教育 > 高考 > synchronized与内存屏障

synchronized与内存屏障

2025/4/28 2:36:52 来源:https://blog.csdn.net/qq_49739667/article/details/147335256  浏览:    关键词:synchronized与内存屏障

以下是关于 Java 中 synchronized 关键字与内存屏障关系的深度解析,结合 JVM 实现细节和底层原理:


一、内存屏障在 synchronized 中的核心作用

内存屏障(Memory Barrier)是 JVM 保证 synchronized 可见性有序性的核心机制,其作用贯穿锁的获取与释放过程:

  1. 可见性保障:确保线程退出同步块时,对共享变量的修改立即刷新到主内存。
  2. 有序性约束:禁止 JVM 对同步块内外的内存操作进行重排序。

二、内存屏障的插入时机与类型

1. 进入同步块时

读屏障(Load Barrier)
强制从主内存加载共享变量的最新值,覆盖线程本地缓存(CPU Cache)。
作用:避免线程读取到过期的旧值。

2. 退出同步块时

写屏障(Store Barrier)
将线程本地缓存中的共享变量值刷新到主内存。
作用:确保其他线程能观察到当前线程的修改。

3. 屏障类型与指令映射
屏障类型硬件指令(x86)功能
LoadLoad无额外指令禁止 Load1 → Load2 重排序
StoreStore无额外指令禁止 Store1 → Store2 重排序
LoadStore无额外指令禁止 Load → Store 重排序
StoreLoadmfence全屏障,禁止 Store → Load 和 Load → Store 重排序

三、锁状态与内存屏障的关联

1. 无锁状态 → 偏向锁

内存屏障:无
实现:仅通过 CAS 修改对象头 Mark Word,无需同步主内存。

2. 偏向锁 → 轻量级锁

内存屏障
释放偏向锁StoreStore 屏障(确保标记字段修改可见)
获取轻量级锁LoadLoad 屏障(保证锁记录加载顺序)

3. 轻量级锁 → 重量级锁

内存屏障
自旋失败:插入 StoreLoad 屏障(强制同步主内存)
阻塞唤醒:依赖 OS 互斥量(Mutex)的原子操作。


四、底层实现细节

1. JVM 屏障插入策略

同步块入口

// 伪代码示例
void monitorenter() {// LoadLoad屏障:确保后续读操作看到之前的写// LoadStore屏障:确保后续写操作不重排到之前的读之前acquireLock();
}

同步块出口

void monitorexit() {// StoreStore屏障:确保之前的写操作完成// StoreLoad屏障:确保写操作对其他线程可见releaseLock();
}
2. x86 架构的优化

StoreLoad 屏障的简化
x86 架构的 mfence 指令性能较高,JVM 在重量级锁中默认使用 mfence 保证全屏障语义。

3. 锁消除与屏障

逃逸分析:若对象未逃逸出同步块,JVM 会消除锁并省略内存屏障,提升性能。


五、实战案例分析

案例 1:双重检查锁(Double-Checked Locking)
public class Singleton {private static volatile Singleton instance;public static Singleton getInstance() {if (instance == null) { // 第一次检查(无屏障)synchronized (Singleton.class) {if (instance == null) { // 第二次检查(有屏障)instance = new Singleton(); // 写屏障保证可见性}}}return instance;}
}

内存屏障作用
synchronized 退出时的 StoreLoad 屏障确保 instance 被其他线程可见。
volatile 关键字额外提供写屏障,防止指令重排序(构造函数未完成时暴露半初始化对象)。

案例 2:状态标志控制
class StateControl {private volatile boolean flag = false;private final Object lock = new Object();public void writer() {synchronized (lock) {flag = true; // 写屏障:刷新到主内存}}public void reader() {synchronized (lock) {if (flag) { // 读屏障:从主内存加载// 执行操作}}}
}

内存屏障作用
• 写操作退出同步块时,StoreStore 屏障确保 flag 的修改对其他线程可见。
• 读操作进入同步块时,LoadLoad 屏障确保读取到最新值。


六、性能优化与调优建议

  1. 减少锁粒度:拆分大同步块,降低屏障插入频率。
  2. 优先使用轻量级锁:通过自旋减少阻塞(JVM 默认启用自适应自旋)。
  3. 避免过度同步:无竞争场景下使用 volatile 替代 synchronized
  4. 监控工具
    jstack 分析锁竞争导致的线程阻塞。
    -XX:+UnlockDiagnosticVMOptions -XX:+LogSafepoint 日志分析屏障插入情况。

七、总结

内存屏障是 synchronized 实现线程安全的核心底层机制,其通过强制内存操作顺序和可见性,解决了多核 CPU 下的乱序执行与缓存不一致问题。开发者需理解其工作原理,结合锁状态升级、JVM 优化策略(如锁消除、锁粗化)设计高效并发程序。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词