synchronized 和 lock 的用法区别

  • synchronized(隐式锁):在需要同步的对象中加入此控制,synchronized 可以加在方法上,也可以加在特定代码块中,括号中表示需要锁的对象。
  • lock(显示锁):需要显示指定起始位置和终止位置。一般使用 ReentrantLock 类做为锁,多个线程中必须要使用一个 ReentrantLock 类做为对象才能保证锁的生效。且在加锁和解锁处需要通过 lock() 和 unlock() 显示指出。所以一般会在 finally 块中写 unlock() 以防死锁。

synchronized 和 lock 性能区别

  • synchronized 是托管给 JVM 执行的,而 lock 是 Java 写的控制锁的代码。在 JDK 1.5 中,synchronize 是性能低效的。因为这是一个重量级操作,需要调用操作接口,导致有可能加锁消耗的系统时间比加锁以外的操作还多。相比之下使用 Java 提供的 Lock 对象,性能更高一些。但是到了 JDK 1.6,发生了变化。synchronize 在语义上很清晰,可以进行很多优化,有适应自旋,锁消除,锁粗化,轻量级锁,偏向锁等等。导致在 JDK 1.6 上 synchronize 的性能并不比 Lock 差。

synchronized 和 lock 机制区别

  • synchronized 原始采用的是 CPU 悲观锁机制,即线程获得的是独占锁。独占锁意味着其 他线程只能依靠阻塞来等待线程释放锁。
  • Lock 用的是乐观锁方式。所谓乐观锁就是,每次不加锁而是假设没有冲突而去完成某项操作,如果因为冲突失败就重试,直到成功为止。乐观锁实现的机制就是 CAS 操作(Compare and Swap)。

用法/性能/机制三段对比是标准答法,但其中”Lock 是乐观锁”的说法需要修正,且还缺一块最重要的内容:功能差异清单与选型决策。本文修正+补全。

修正:Lock 不是乐观锁

ReentrantLock 默认实现与 synchronized 一样是悲观锁(竞争者 park 阻塞等待)。”乐观锁=CAS”描述的是 AQS 内部获取锁的动作用 CAS 改 state,而非 Lock 的并发哲学。把”Lock=乐观锁”当结论背会在面试追问下崩塌。准确表述:两者都是悲观互斥锁,差异在功能面与实现层。

功能差异清单(选型的真正依据)

能力 synchronized ReentrantLock
释放方式 自动(出块/异常均释放) 手动 unlock,必须 finally
等待可中断 不可 lockInterruptibly
超时可放弃 不可 tryLock(timeout)
公平性 非公平 构造参数可选公平
条件队列 单一 wait/notify 多个 Condition 分组唤醒
锁绑定 JVM 关键字 API 对象,可传递/组合
查询能力 无 isLocked/getQueueLength 等监控 API

三个”只有 Lock 能”的场景:

  • 限时尝试:tryLock(50ms) 失败走降级路径(缓存/排队),避免请求堆积等锁
  • 可中断等待:用户取消请求时中断正在等锁的线程,synchronized 做不到
  • 多条件精确唤醒:生产者-消费者用 notFull/notEmpty 两个 Condition,避免 notifyAll 全量唤醒的浪费

性能对比的现代结论

JDK6 之后 synchronized 引入偏向锁/轻量级锁/自适应自旋/锁消除/锁粗化,无竞争与低竞争场景开销极小;ReentrantLock 基于 AQS,CAS 改 state + park 阻塞,两者在多数基准下差距在噪声范围内。**”性能”不再是选型理由,功能需求才是**。JDK15 起偏向锁默认禁用(撤销成本高),但轻量级路径仍在,结论不变。

使用规范

synchronized:

  • 锁对象选私有 final 对象或 this,避免锁字符串/公开对象被外部干扰
  • 临界区最小化:IO、远程调用、sleep 移出锁外

ReentrantLock:

lock.lock();
try {
criticalSection();
} finally {
lock.unlock(); // 唯一正确姿势:finally 释放
}
  • lock() 必须在 try 之外(lock 本身抛异常则不应 unlock)
  • 公平锁吞吐低于非公平锁(减少切换机会),仅在有饥饿要求时启用
  • Condition 的 await 也要放在循环中检查条件(防虚假唤醒),与 wait 规范相同

选型决策树

  1. 只需互斥、无特殊需求 → synchronized(不会忘释放,JVM 持续优化)
  2. 需要超时/中断/公平/多条件之一 → ReentrantLock
  3. 只需单变量原子复合 → atomic 包(比两者都轻)
  4. 读多写极少 → ReadWriteLock / StampedLock(注意 StampedLock 不可重入、不支持条件变量)

synchronized 与 Lock 的区别,历史性能叙事已过期,今天的答案在功能面:synchronized 是”够用且安全”的默认,Lock 是”需要控制等待行为时”的升级。把选型建立在功能需求而非性能传说上,这个题目就答到了现代版本。