Lock 与 synchronized 区别笔记

Lock 与 synchronized 的核心区别

1. 功能覆盖与扩展

  • **Lock**:

    几乎能实现 synchronized 的所有基础功能(保证线程安全、同步代码块),且具备 synchronized 不支持的高级特性:

    • 锁投票(如通过 tryLock() 实现多线程竞争时的灵活选择);
    • 定时锁等候(tryLock(long time, TimeUnit unit) 避免无限阻塞);
    • 可中断锁(lockInterruptibly() 允许中断等待锁的线程);
    • 支持公平 / 非公平锁选择、多条件变量(Condition)等。
  • **synchronized**:

    功能相对基础,仅支持最基本的同步需求,不具备上述高级特性:

    • 无法通过投票获取锁,一旦开始等待则必须等到锁释放;
    • 不能中断等待锁的线程;
    • 锁的释放只能在获取锁的同一堆栈帧中完成(自动释放,无法手动控制时机)。

2. 实现层面与释放机制

  • **Lock**:

    • 是 JDK 5 引入的 API 层面的锁(位于 java.util.concurrent.locks 包),属于代码级别的实现;
    • 必须手动释放锁:需在 finally 块中显式调用 unlock(),否则可能导致锁长期占用,引发死锁或线程阻塞。
  • **synchronized**:

    • 是 Java 语言内置的关键字,属于 JVM 层面的实现(由字节码指令 monitorenter/monitorexit 控制);
    • 自动释放锁:当同步代码块执行完毕或发生异常时,JVM 会自动释放锁,无需手动干预。

3. 抽象性与灵活性

  • **Lock**:

    是 锁的抽象框架ReentrantLock 等是其具体实现,支持通过接口定义灵活扩展,适配不同场景(如公平锁、读写锁 ReentrantReadWriteLock 等)。

  • **synchronized**:

    是固定的同步机制,实现逻辑封装在 JVM 中,用户无法自定义扩展,灵活性较低。

4. 历史与适用场景

  • **synchronized**:

    是 Java 早期就存在的同步机制,实现简单、易用,适合基础同步场景(如简单的共享资源操作),且 JVM 对其优化较好(如偏向锁、轻量级锁)。

  • **Lock**:

    是后期为弥补 synchronized 不足而设计的,适合复杂并发场景(如需要中断等待、定时获取锁、多条件唤醒等),但使用成本较高(需手动管理锁释放)。

总结

维度 Lock synchronized
功能 基础功能 + 高级特性(定时、中断、公平锁等) 仅基础同步功能
实现层面 API 层面(代码级) JVM 层面(关键字)
锁释放 手动释放(finally 中 unlock() 自动释放(JVM 控制)
灵活性 高(可扩展、多场景适配) 低(固定实现)
适用场景 复杂并发需求 简单同步需求