ReentrantLock
是 Java 中用于进行显式锁定的类,它提供了与 synchronized
关键字类似的互斥性和可重入性,但相比于 synchronized
,它提供了更灵活的锁定方式。下面对 ReentrantLock
进行详解:
一、ReentrantLock 是什么?
ReentrantLock 是 java.util.concurrent.locks 包下的一个锁实现类。它的名字中的 “Reentrant” 意味着锁是可重入的,一个线程可以多次获得同一把锁。
1、ReentrantLock 的原理和设计思路
ReentrantLock 的原理是基于 AQS(AbstractQueuedSynchronizer,抽象队列同步器)实现的。AQS 使用了一个类似 CLH 队列锁的机制,其中等待线程会形成一个链表,等待锁的线程会被加入到链表的尾部。每个节点(线程)维护了一个状态信息,通过这个状态信息来控制线程的等待和唤醒。
设计思路主要包括:
- 可重入性: 允许同一线程多次获取锁,避免死锁情况。
- 公平锁和非公平锁: 可以选择是否公平,公平锁按照请求的顺序分配锁;非公平锁允许“插队”,某个线程在等待队列中尝试直接获取锁。
- Condition 条件队列: 提供了 Condition 对象,可以通过它实现更灵活的线程通信。
- 中断响应: 锁支持对线程的中断响应,一个线程在等待锁的过程中可以被中断。
- 可定时锁等待: 在指定的时间内尝试获取锁,避免无限期等待。
2、设计思路可用于其他场景
ReentrantLock 的设计思路,尤其是使用 AQS 实现的方式,可以应用于其他需要实现同步、互斥、等待通知的场景。比如自定义的同步器、线程池的任务队列等。
二、为什么使用 ReentrantLock
ReentrantLock 的作用和特点
1、作用:
提供了一种更灵活、可定制的锁机制,用于解决多线程并发访问共享资源的同步问题。
2、特点:
- 可重入性: 同一线程可以多次获得同一把锁。
- 公平性: 可以选择是公平锁还是非公平锁。
- Condition 支持: 可以通过 newCondition 方法创建 Condition 对象,实现更复杂的线程间通信。
- 锁中断响应: 线程在等待锁的过程中可以被中断。
- 可定时等待: 支持在指定时间内尝试获取锁。
三、ReentrantLock 的使用
使用 ReentrantLock 一般包括以下步骤:
- 创建锁对象: ReentrantLock lock = new ReentrantLock();
- 加锁: 使用 lock() 方法加锁。
- 解锁: 使用 unlock() 方法解锁。通常在 finally 块中确保释放锁,防止发生异常时锁无法释放。
- 可选: 使用 tryLock() 方法尝试非阻塞地获取锁,使用 lockInterruptibly() 方法可以对中断进行响应。
总的来说,ReentrantLock 提供了一种更灵活和可控的锁定机制,适用于对锁控制有更高要求的多线程场景。