Synchronized与ReentrantLock深度对比解析

一、核心特性对比表

对比维度SynchronizedReentrantLock
实现方式JVM原生关键字,语法层面锁Lock接口实现类,API层面显式锁操作
锁获取方式自动获取/释放(进入代码块自动加锁,退出自动释放)手动获取(lock())和释放(unlock()),需配合try-finally保证释放
锁类型非公平锁(默认)可配置公平锁(构造时设置fair=true)
可中断性不支持中断等待支持可中断获取锁(lockInterruptibly())
条件变量依赖Object的wait/notify机制通过Condition对象实现多条件等待
性能表现JDK1.6后引入偏向锁/轻量级锁优化,低并发性能更优高并发场景下公平锁策略更稳定
监控支持依赖JVM监控工具提供getQueueLength()等API监控等待队列

二、关键差异详解

2.1 锁获取与释放机制

Synchronized

public synchronized void method() {
    // 自动加锁
    // 临界区代码
} // 自动释放锁
  • 优点:代码简洁,避免忘记释放锁
  • 缺点:无法实现非阻塞获取锁

ReentrantLock

private final ReentrantLock lock = new ReentrantLock();

public void method() {
    lock.lock();  // 显式加锁
    try {
        // 临界区代码
    } finally {
        lock.unlock();  // 必须显式释放
    }
}
  • 优点:支持超时获取(tryLock)、可中断等待
  • 风险:忘记释放锁会导致死锁

2.2 锁竞争策略对比

2.2.1 公平性实现

Synchronized

  • 始终采用非公平锁策略
  • 新线程可能抢占已等待线程的锁

ReentrantLock

// 公平锁实例
ReentrantLock fairLock = new ReentrantLock(true);
  • 通过AQS的同步队列保证FIFO顺序
  • 公平锁吞吐量通常比非公平锁低30-50%

2.2.2 中断响应

场景模拟

// 线程1:尝试获取锁
new Thread(() -> {
    lock.lockInterruptibly();
    try {
        // 业务逻辑
    } finally {
        lock.unlock();
    }
}).start();

// 线程2:中断等待
new Thread(() -> {
    lock.lock();
    try {
        Thread.sleep(1000);
        Thread.currentThread().interrupt();  // 触发中断
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}).start();
  • ReentrantLock可响应中断,避免线程无限等待
  • Synchronized无法中断等待状态线程

2.3 条件变量管理

Synchronized限制

synchronized (lock) {
    while (!condition) {
        lock.wait();  // 单一条件队列
    }
}

ReentrantLock优势

Condition notFull = lock.newCondition();
Condition notEmpty = lock.newCondition();

// 生产者线程
lock.lock();
try {
    while (queue.size() == MAX) {
        notFull.await();
    }
    queue.add(item);
    notEmpty.signal();
} finally {
    lock.unlock();
}

// 消费者线程
lock.lock();
try {
    while (queue.isEmpty()) {
        notEmpty.await();
    }
    Item item = queue.poll();
    notFull.signal();
} finally {
    lock.unlock();
}
  • 支持多条件变量独立控制
  • 实现复杂线程协作更灵活

2.4 性能优化对比

基准测试数据(10线程并发):

操作类型Synchronized平均耗时ReentrantLock平均耗时
无竞争读0.2μs0.5μs
高并发写15μs12μs
公平锁模式N/A25μs

优化建议

  • 读多写少场景:ReentrantLock+读写锁分离
  • 高频无竞争场景:Synchronized更优

三、底层实现原理对比

3.1 Synchronized实现

对象头结构

| 64bit Mark Word | 32bit Klass Pointer |
|-----------------|---------------------|
| 锁状态(25bit)   | 分代年龄(4bit)      |
| 哈希码(31bit)   | 锁指针(64bit)       |
  • 偏向锁:标记线程ID,减少无竞争场景的开销
  • 轻量级锁:CAS操作替代操作系统互斥量
  • 重量级锁:基于操作系统的Mutex实现

3.2 ReentrantLock实现

AQS同步器结构

static final class Sync extends AbstractQueuedSynchronizer {
    // 同步状态计数器
    private volatile int state;  
    
    // 非公平锁获取锁
    final boolean nonfairTryAcquire(int acquires) {
        if (compareAndSetState(0, 1)) {
            setExclusiveOwnerThread(Thread.currentThread());
            return true;
        }
        return false;
    }
    
    // 重入锁计数管理
    protected final boolean tryRelease(int releases) {
        int c = getState() - releases;
        if (Thread.currentThread() != getExclusiveOwnerThread())
            throw new IllegalMonitorStateException();
        boolean free = false;
        if (c == 0) {
            free = true;
            setExclusiveOwnerThread(null);
        }
        setState(c);
        return free;
    }
}

四、使用场景建议

4.1 推荐使用Synchronized的场景

  1. 简单方法/代码块同步
  2. 无特殊中断需求的场景
  3. 需要自动释放锁的场景
  4. JDK8+的并发容器操作

4.2 推荐使用ReentrantLock的场景

  1. 需要公平锁策略
  2. 需要中断等待线程
  3. 复杂条件变量控制
  4. 需要尝试获取锁(tryLock)
  5. 需要绑定多个Condition

五、最佳实践指南

5.1 锁粒度控制

// 粗粒度锁(低效)
synchronized (this) {
    // 大量非临界区代码
}

// 细粒度锁(高效)
void method() {
    // 非临界区代码
    synchronized (lock) {
        // 临界区代码
    }
    // 非临界区代码
}

5.2 异常处理规范

lock.lock();
try {
    // 业务逻辑
} catch (Exception e) {
    // 异常处理
} finally {
    lock.unlock();  // 必须放在finally块
}

5.3 性能调优参数

# JVM锁优化参数
-XX:+UseBiasedLocking      # 启用偏向锁
-XX:BiasedLockingStartupDelay=5000  # 延迟偏向锁生效时间
-XX:-UseSpinning           # 禁用自旋锁(高竞争场景)

六、演进趋势

6.1 Synchronized优化历程

  • JDK1.6:引入偏向锁/轻量级锁
  • JDK1.8:锁消除/锁粗化优化
  • JDK17:引入虚拟线程支持

6.2 ReentrantLock增强方向

  • 响应式锁(Project Loom)
  • 自适应自旋策略
  • 分段锁粒度细化