synchronized与Lock深度对比

Java并发编程:synchronized与Lock深度对比

  1. 基本概念

1.1 synchronized
synchronized是Java内置的关键字,属于JVM层面的锁机制。它通过对象监视器(Monitor)实现同步,具有自动获取和释放锁的特性。

// 同步方法
public synchronized void syncMethod() {
    // 代码
}

// 同步代码块
public void method() {
    synchronized(this) {
        // 代码
    }
}

1.2 Lock
Lock是Java并发包(java.util.concurrent.locks)提供的接口,属于API层面的锁机制。最常用的实现类是ReentrantLock

private Lock lock = new ReentrantLock();

public void method() {
    lock.lock();
    try {
        // 代码
    } finally {
        lock.unlock(); // 必须手动释放
    }
}
  1. 核心区别对比
特性 synchronized Lock (ReentrantLock)
实现方式 JVM内置关键字 Java类库实现
锁获取/释放 自动 手动(lock()/unlock())
锁类型 非公平锁 可配置公平/非公平锁
可中断性 不可中断 支持(lockInterruptibly())
尝试获取锁 不支持 支持(tryLock())
超时机制 不支持 支持(tryLock(time, unit))
条件变量 单一条件(wait/notify) 多条件(newCondition())
性能 JDK6后优化,低竞争时性能好 高竞争时性能更优
锁粒度 方法或代码块级别 可更细粒度控制
  1. 底层原理

3.1 synchronized实现
• 锁升级机制:偏向锁→轻量级锁→重量级锁

• 对象头Mark Word存储锁状态

• Monitor机制:每个对象关联一个Monitor,包含_EntryList和_WaitSet

3.2 Lock实现
• 基于AQS(AbstractQueuedSynchronizer)框架

• 使用CLH队列管理等待线程

• 支持公平/非公平两种获取锁方式

  1. 高级特性

4.1 Lock特有功能

// 1. 尝试获取锁
if (lock.tryLock()) {
    try {
        // 获取锁成功
    } finally {
        lock.unlock();
    }
}

// 2. 可中断获取锁
try {
    lock.lockInterruptibly();
    // ...
} catch (InterruptedException e) {
    // 处理中断
}

// 3. 多条件变量
Condition notFull = lock.newCondition();
Condition notEmpty = lock.newCondition();

4.2 synchronized优化
• 锁消除:JVM检测到不可能存在共享数据竞争时消除锁

• 锁粗化:将连续的同步块合并为一个更大的同步块

• 自适应自旋:根据历史数据动态调整自旋次数

  1. 使用场景建议

优先使用synchronized
• 简单的同步需求

• 锁的获取和释放在同一方法内

• 不需要高级功能(如超时、中断等)

选择Lock的情况
• 需要公平锁

• 需要尝试非阻塞获取锁

• 需要多个条件变量

• 锁需要在多个方法间传递

• 高竞争环境下对性能有更高要求

  1. 实际案例

6.1 生产者-消费者模型(Lock实现)

class Buffer {
    private final Lock lock = new ReentrantLock();
    private final Condition notFull = lock.newCondition();
    private final Condition notEmpty = lock.newCondition();
    
    public void produce() {
        lock.lock();
        try {
            while (isFull()) {
                notFull.await();
            }
            // 生产...
            notEmpty.signal();
        } finally {
            lock.unlock();
        }
    }
}

6.2 单例模式(synchronized实现)

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;
    }
}
  1. 总结

synchronizedLock都是Java中实现线程同步的有效机制,各有优缺点。理解它们的底层原理和适用场景,才能在实际开发中做出合理选择。对于大多数简单场景,synchronized已经足够;当需要更灵活的锁控制时,Lock是更好的选择。

你可能感兴趣的:(Java学习,java)