Java并发编程——synchronized的实现原理与应用

Java synchronized 的实现原理与应用

synchronized 是 Java 提供的一种内置关键字,用于实现线程同步,确保多线程环境下对共享资源的互斥访问。它是 JVM 层面的机制,简单易用,但底层实现较为复杂。下面我从实现原理应用两个方面详细解释。

1. 实现原理

synchronized 的核心是基于 Monitor(监视器) 机制实现的 Monitor 是对象头(Object Header)中的一部分,包含锁信息。JVM 通过字节码指令和锁优化来保证线程安全。

1.1 基本工作流程
  • 加锁(Lock) :当线程执行 synchronized 时,JVM 插入 monitorenter 字节码指令。线程尝试获取对象的 Monitor:
    • 如果 Monitor 空闲,线程持有它(成为 Owner),进入同步块。
    • 如果已被其他线程持有,当前线程进入阻塞队列(等待队列),直到 Owner 线程释放。
  • 解锁(Unlock) :执行到同步块末尾或异常时,插入 monitorexit 字节码,释放 Monitor,其他等待线程竞争获取。
  • 异常处理 :即使发生异常,monitorexit 也会自动执行(通过异常表机制),确保锁释放。
1.2 锁存储与优化(HotSpot JVM 实现)

synchronized 的锁不是简单的互斥锁,而是通过锁升级机制优化性能,避免不必要的开销。锁信息存储在对象头中(Mark Word,64 位中约占 64 位用于锁状态)。

锁升级过程(从低到高开销):

  1. 无锁状态:对象未被同步时。
  2. 偏向锁(Biased Locking):适用于单线程或低竞争场景。首次加锁时,Mark Word 记录线程 ID,后续同一线程无需 CAS(Compare-And-Swap)即可获取锁。竞争时升级。
  3. 轻量级锁(Lightweight Locking):中等竞争。线程在栈帧中创建锁记录(Lock Record),通过 CAS 更新 Mark Word 指针指向它。失败时自旋重试(自适应自旋,避免立即阻塞)。
  4. 重量级锁(Heavyweight Locking):高竞争。Mark Word 指向 Monitor 对象(内核态数据结构),线程阻塞/唤醒需 OS 调度(上下文切换,开销大)。
锁类型 适用场景 存储位置 优化机制 开销
偏向锁 单线程访问 Mark Word(线程 ID) 无 CAS,直接偏向 最低
轻量级锁 低竞争多线程 Mark Word + 栈锁记录 CAS + 自旋
重量级锁 高竞争 Mark Word + 内核 Monitor OS 阻塞/唤醒
  • 升级触发 :竞争加剧时自动升级(不可逆)。JVM 参数如 -XX:BiasedLockingStartupDelay=0 可控制偏向锁延迟启用。
  • 原子性与可见性synchronized 确保原子性 (操作不可中断)和可见性 (释放锁时刷新缓存,其他线程可见最新值)。底层依赖内存屏障(Memory Barrier)指令(如 mfence)。
1.3 底层字节码示例

编译后字节码:

复制代码
0: aload_1          // 加载 obj
1: dup
2: astore_2         // 备份 obj
3: monitorenter     // 加锁
4: aload_2          // ...
...                // 同步代码
N: aload_2
N+1: monitorexit    // 解锁
N+2: goto N+5
N+3: astore_2       // 异常时释放锁
N+4: aload_2
N+5: monitorexit
N+6: athrow         // 重新抛异常
2. 应用

synchronized 广泛用于线程安全场景,如共享变量、单例模式、线程池等。它简单,但需注意死锁风险(多锁嵌套)。优先用于简单同步;复杂场景可考虑 ReentrantLock(更灵活)。

2.1 常见应用形式
  • 同步方法 :修饰实例方法(锁 this)或静态方法(锁 Class 对象)。

    java 复制代码
    public synchronized void increment() { i++; }  // 锁 this
    public static synchronized void staticIncrement() { i++; }  // 锁 Counter.class
  • 同步代码块 :粒度更细,指定任意对象作为锁。

    java 复制代码
    synchronized (lockObj) {  // lockObj 可为任意对象
        // 临界区代码
    }
2.2 典型应用场景
场景 应用方式 说明
计数器线程安全 同步方法或代码块包裹 i++ 防止竞态条件(如前文 Counter 示例)。
单例模式 静态同步方法或双重检查锁定 确保实例唯一:synchronized (Singleton.class) { if (instance == null) instance = new ...; }
生产者-消费者 同步块 + wait()/notify() 锁同一对象,wait() 释放锁,notify() 唤醒。
集合线程安全 同步包装:Collections.synchronizedList(list) 内部用 synchronized 包装方法。
数据库连接池 同步获取/释放连接 避免并发超限。
2.3 示例:线程安全计数器
java 复制代码
class SafeCounter {
    private int count = 0;
    private final Object lock = new Object();  // 专用锁对象

    public void increment() {
        synchronized (lock) {  // 细粒度锁
            count++;
        }
    }

    public int getCount() {
        synchronized (lock) {
            return count;
        }
    }
}

// 多线程测试(类似前文)
public class SyncDemo {
    public static void main(String[] args) {
        SafeCounter counter = new SafeCounter();
        List<Thread> threads = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            threads.add(new Thread(() -> {
                for (int j = 0; j < 10000; j++) {
                    counter.increment();
                }
            }));
        }
        threads.forEach(Thread::start);
        threads.forEach(t -> {
            try { t.join(); } catch (InterruptedException e) { e.printStackTrace(); }
        });
        System.out.println(counter.getCount());  // 输出: 100000(精确)
    }
}
  • 无 synchronized:可能输出 < 100,000(丢失更新)。
  • 优势 :简单、无需显式锁管理;劣势:不可中断,性能在高竞争时较低。
3. 注意事项与最佳实践
  • 性能 :低竞争用 synchronized,高竞争考虑 ConcurrentHashMapLock
  • 死锁避免:统一加锁顺序、超时机制。
  • Java 版本演进:JDK 6 引入锁优化,提升性能;JDK 8+ 偏向锁默认启用。
  • 替代品volatile(仅可见性)、Lock 接口(可重入、可公平)、JUC 包(高级并发工具)。
相关推荐
yi碗汤园5 小时前
【超详细】C#自定义工具类-StringHelper
开发语言·前端·unity·c#·游戏引擎
sali-tec5 小时前
C# 基于halcon的视觉工作流-章49-网面破损
开发语言·图像处理·算法·计算机视觉·c#
YuanlongWang5 小时前
c# ABP vNext 框架详解及其模块化开发思想介绍
开发语言·c#
张人玉6 小时前
WPF布局控件(界面骨架核心)
开发语言·c#·wpf·布局控件
闲人编程6 小时前
使用MLflow跟踪和管理你的机器学习实验
开发语言·人工智能·python·机器学习·ml·codecapsule
看兵马俑的程序员6 小时前
RAG实现-本地PDF内容加载和切片
开发语言·python·pdf
专注前端30年6 小时前
【JavaScript】reduce 方法的详解与实战
开发语言·前端·javascript
两个人的幸福online6 小时前
php使用腾讯云服务
开发语言·php·腾讯云
无敌最俊朗@6 小时前
C++ STL Deque 高频面试题与答案
开发语言·c++