Java多线程与并发(11-26)-JUC锁- ReentrantLock详解.pdf
Java中的ReentrantLock是Java并发包(java.util.concurrent.locks)中的一个高级锁,它是可重入的,意味着一个线程可以多次获取同一锁。在深入ReentrantLock之前,我们首先需要了解Java并发编程的基础,特别是Java内存模型和线程同步机制。 **可重入锁与可重入性**可重入锁允许同一个线程反复进入它已经拥有的锁所保护的代码段。在Java中,synchronized关键字和ReentrantLock都具有可重入性。这种特性解决了递归调用中可能出现的死锁问题。当一个线程尝试获取已经持有的锁时,它会被允许再次获取,而不是阻塞或抛出异常。 **ReentrantLock与AQS(AbstractQueuedSynchronizer)** ReentrantLock的核心实现依赖于AQS,这是一个抽象的队列同步器。AQS维护了一个状态字段和一个FIFO等待队列,用于管理线程的同步。ReentrantLock的内部类Sync继承自AQS,进一步分为FairSync(公平锁)和NonfairSync(非公平锁)两个子类。公平锁确保线程按照它们请求锁的顺序获取锁,而非公平锁则不保证这种顺序,可能会有线程插队获取锁。 **公平锁与非公平锁实现** - **公平锁**:在FairSync中,线程获取锁时会检查队列中是否有其他线程在等待。如果有,即使锁是可用的,线程也会等待,直到队列为空或成为队列的第一个元素。这样保证了等待时间最长的线程优先获取锁。 - **非公平锁**:NonfairSync中,线程获取锁时不会检查队列状态,而是直接尝试获取锁。这可能导致某些线程即使在队列中,也可能在其他线程之前获取到锁,提高锁的吞吐量,但可能导致不公平现象。 **ReentrantLock默认实现** ReentrantLock默认实现是非公平锁,可以通过构造函数传入参数true来创建公平锁。 **ReentrantLock与synchronized的对比** 1. **控制粒度**:synchronized是隐式的,而ReentrantLock是显式的,提供了更多的控制选项。 2. **中断支持**:ReentrantLock支持可中断的获取锁,而synchronized不支持。 3. **公平性**:ReentrantLock可配置为公平锁,而synchronized总是非公平的。 4. **锁绑定条件**:ReentrantLock可以通过newCondition()创建多个条件变量,每个条件对应一组线程,而synchronized只有一个隐含的条件。 5. **锁的粒度**:ReentrantLock的锁可以更细粒度地控制,比如可以只锁住部分代码。 **源码分析** ReentrantLock类实现了Lock接口,提供了lock()、unlock()等方法。Sync类是内部抽象类,继承自AQS,它有两个子类NonfairSync和FairSync。Sync类中有lock()抽象方法,以及nonfairTryAcquire()和tryRelease()等具体实现。nonfairTryAcquire()方法尝试获取锁,公平或非公平取决于具体子类的实现。在tryAcquire()方法中,会检查当前线程是否持有锁(通过getState()和getExclusiveOwnerThread()),如果是,则增加重入计数;如果不是,尝试通过compareAndSetState()原子操作设置状态,成功则获取锁。 tryRelease()方法释放锁,会减少重入计数,当计数为零时,释放锁,并唤醒等待的线程。 ReentrantLock提供了一种灵活且高效的线程同步机制,既满足了公平性需求,又允许优化性能,是Java并发编程中的重要工具。理解其工作原理和源码细节,对于提升并发编程能力大有裨益。
下载地址
用户评论