参考答案:
ReentrantLock
是 Java 并发包中的一种显式锁实现,它提供了比 synchronized
更强大的功能,能够灵活地控制线程的加锁和释放锁。它是 java.util.concurrent.locks
包中的一部分,常用于实现线程同步控制,支持公平性和重入等特性。
ReentrantLock
是一种可重入的锁,即同一个线程在获得锁后,可以多次进入该锁而不发生死锁。这种特性使得 ReentrantLock
能够支持递归调用的场景。ReentrantLock
是 Lock
接口的实现,它的主要优点是:
ReentrantLock
的实现主要依赖于 java.util.concurrent.locks.AbstractQueuedSynchronizer
(AQS)类。AQS 是一个提供了先进先出的同步队列的抽象类,它为实现各种同步器(如锁、信号量等)提供了通用的框架。
ReentrantLock
基于 AQS 来实现线程同步。它通过 AQS
提供的 acquire 和 release 方法来控制锁的获取和释放。
ReentrantLock
内部通过一个 int
类型的变量 state
来记录锁的状态。state
的值主要表示两个方面的信息:
锁是否被占用
锁的重入次数(即同一个线程获取锁的次数)
当 state
为 0 时,锁是空闲的。
当 state
大于 0 时,锁被占用,state
的值表示当前线程重入锁的次数。
lock()
方法)当调用 ReentrantLock
的 lock()
方法时,实际执行的是 AQS
的 acquire()
方法,流程如下:
state
等于 0,表示锁没有被占用,当前线程可以通过 compareAndSetState
操作将 state
设置为 1,即占用锁,并将当前线程设置为持有锁的线程。state
大于 0,表示锁已经被其他线程占用,当前线程会进入 AQS 的等待队列中,等待锁被释放。具体来说,线程会尝试通过 acquireQueued
方法进入队列等待,并在适当的时候重新尝试获取锁。ReentrantLock
会通过增加 state
的值来支持重入锁操作(即允许当前线程多次调用 lock()
方法)。1public void lock() { 2 if (Thread.currentThread() == getOwner()) { 3 state++; 4 return; 5 } 6 // 非公平锁的获取 7 if (!tryAcquire(state)) { 8 enqueue(Thread.currentThread()); 9 } 10}
unlock()
方法)当调用 ReentrantLock
的 unlock()
方法时,实际执行的是 AQS
的 release()
方法,流程如下:
state
减 1。state
为 0,表示该线程已完全释放了锁,它会调用 release
方法来通知其他线程并唤醒等待队列中的线程。state
大于 0,表示当前线程仍然持有锁,其他线程无法获取锁。1public void unlock() { 2 if (Thread.currentThread() != getOwner()) { 3 throw new IllegalMonitorStateException(); 4 } 5 state--; 6 if (state == 0) { 7 setOwner(null); 8 // 唤醒等待队列中的下一个线程 9 release(); 10 } 11}
ReentrantLock
提供了公平锁和非公平锁的选择:
在创建 ReentrantLock
时,通过传入一个布尔值来指定是否启用公平锁:
1ReentrantLock lock = new ReentrantLock(true); // 公平锁 2ReentrantLock lock = new ReentrantLock(false); // 非公平锁
AQS 是 ReentrantLock
内部实现的核心类。它通过一个同步队列来管理线程的等待和唤醒。每个线程在获取锁时,如果锁不可用,就会被挂起,并加入到 AQS 的队列中,等待被唤醒后重新尝试获取锁。
state
来记录当前的同步状态。在 ReentrantLock
中,state
表示锁的占用情况。AQS 的实现依赖于 acquire
和 release
方法来控制线程的加锁和释放。当线程释放锁时,如果有其他线程等待锁,则会唤醒它们,并重新争夺锁。
ReentrantLock
支持线程的重入性,允许同一线程多次获得锁,而不会发生死锁。ReentrantLock
支持响应中断,线程可以在等待锁时被中断,从而避免长时间阻塞。ReentrantLock
提供了 Condition
机制,可以更灵活地控制线程的同步。ReentrantLock
的实现比 synchronized
更复杂,使用时需要手动释放锁,否则会导致死锁。ReentrantLock
比 synchronized
提供了更多功能,但由于额外的复杂性,它的性能可能比 synchronized
略低。ReentrantLock
示例1public class ReentrantLockExample { 2 private final ReentrantLock lock = new ReentrantLock(); 3 4 public void criticalSection() { 5 lock.lock(); 6 try { 7 // 执行临界区代码 8 System.out.println("In critical section"); 9 } finally { 10 lock.unlock(); 11 } 12 } 13}
最近更新时间:2024-12-06