本文目录导读:

Lock 接口相比于 synchronized 关键字,提供了更灵活、更丰富的锁机制,主要优势体现在以下几个方面:
尝试非阻塞获取锁
- synchronized:如果锁被其他线程持有,当前线程会一直阻塞,直到获得锁,无法中断这个等待过程。
- Lock:提供了
tryLock()方法,可以尝试获取锁,如果锁不可用,立即返回 false,线程可以去做其他事情,而不会阻塞等待。Lock lock = new ReentrantLock(); if (lock.tryLock()) { try { // 临界区 } finally { lock.unlock(); } } else { // 锁不可用,执行其他逻辑 }
可中断的锁获取
- synchronized:一旦线程进入阻塞状态等待锁,无法响应中断(
interrupt()),除非线程获得了锁,否则无法退出等待。 - Lock:提供了
lockInterruptibly()方法,在等待锁的过程中,如果其他线程中断了当前线程,它会抛出InterruptedException并释放等待,这对于需要处理长时间等待或可取消任务的场景非常有用。
支持超时
- synchronized:没有超时机制,可能会因为死锁或长时间持有锁而导致线程无限期阻塞。
- Lock:提供了
tryLock(long time, TimeUnit unit)方法,线程可以指定一个等待超时时间,如果在指定时间内没拿到锁,就放弃等待,返回 false,这可以有效避免死锁。
更灵活的锁释放(手动控制)
- synchronized:锁的获取和释放完全由 JVM 自动管理,代码块执行完毕或抛出异常时自动释放,虽然简单,但不够灵活。
- Lock:需要显式地调用
lock()和unlock(),这允许你在不同的代码块或方法中获取和释放锁,甚至可以在一个方法中获取锁,在另一个方法中释放(虽然不推荐,但技术上可行),同时也要求你必须在finally块中释放锁,以避免死锁。
支持多个条件变量(Condition)
-
synchronized:只能依赖于
Object的wait()/notify()/notifyAll()方法进行线程间协作,且只能有一个等待队列。 -
Lock:通过
newCondition()可以创建多个Condition对象,每个Condition可以拥有自己的等待集(wait set),这可以实现更精细的线程同步控制,可以有一个“缓冲区满”的条件和一个“缓冲区空”的条件,不同的线程可以在不同条件下等待和唤醒。Lock lock = new ReentrantLock(); Condition notFull = lock.newCondition(); Condition notEmpty = lock.newCondition(); // 生产者等待 notFull,消费者等待 notEmpty
支持公平锁
- synchronized:锁的获取不保证公平性,即等待时间最长的线程不一定最先获得锁,这也可能导致线程“饥饿”(某些线程长时间得不到执行)。
- Lock:
ReentrantLock的构造函数可以传入boolean fair参数。new ReentrantLock(true)创建一个公平锁,公平锁会按照线程请求锁的顺序(FIFO)来分配锁,从而避免线程饥饿。
提供读写锁(ReadWriteLock)
- synchronized:无法区分读和写操作,无论读还是写,都会阻塞所有其他线程。
- Lock:提供了
ReadWriteLock接口及其实现ReentrantReadWriteLock,它维护了一对锁:- 读锁:多个线程可以同时持有读锁(只要没有写锁)。
- 写锁:写锁是独占的(其他读或写线程都不能持有)。
- 这种机制在读多写少的场景下能显著提高并发性能。
总结对比表格
| 特性 | synchronized | Lock |
|---|---|---|
| 锁类型 | 可重入、非公平锁 | 可重入、公平/非公平锁、读写锁 |
| 获取锁方式 | 阻塞等待,无法中断 | 阻塞、非阻塞尝试(tryLock)、可中断(lockInterruptibly)、超时 |
| 释放锁 | 自动(结束代码块或异常) | 手动,必须在 finally 中调用 unlock() |
| 条件变量 | 单个(Object.wait/notify) | 多个(newCondition) |
| 性能 | 较少竞争时,JVM 优化后性能接近 | 高竞争场景下,更灵活,通常性能更好 |
| 代码复杂性 | 简单,无需手动释放 | 复杂,需手动处理锁获取和释放 |
什么时候用哪个?
- 更推荐
synchronized:对于简单的同步需求,代码更简洁、不易出错,且 JVM 本身会对synchronized进行持续优化(如锁粗化、锁消除、偏向锁等)。 - 推荐
Lock:当需要更高级的锁特性时(如超时、可中断、尝试获取、读写锁、多个条件变量、公平锁),这些场景下Lock提供的灵活性是synchronized无法替代的。
简而言之:Lock 是 synchronized 的“瑞士军刀”版本,功能更强大,但使用时需要更小心(尤其是手动释放锁)。