随时随地阅读更多技术实战干货,获取项目源码、学习资料,请关注源代码社区公众号(ydmsq666)、博主微信(guyun297890152)、QQ技术交流群(183198395)。
一、概述
结构:
java.lang.Object
java.util.concurrent.locks.ReentrantLock
声明:public class ReentrantLock extends Object implements Lock, Serializable
一个可重入的互斥锁 Lock
,它具有与使用 synchronized
方法和语句所访问的隐式监视器锁相同的一些基本行为和语义,但功能更强大。
ReentrantLock
将由最近成功获得锁,并且还没有释放该锁的线程所拥有。当锁没有被另一个线程所拥有时,调用 lock
的线程将成功获取该锁并返回。如果当前线程已经拥有该锁,此方法将立即返回。可以使用 isHeldByCurrentThread()
和 getHoldCount()
方法来检查此情况是否发生。
此类的构造方法接受一个可选的公平 参数。当设置为 true
时,在多个线程的争用下,这些锁倾向于将访问权授予等待时间最长的线程。否则此锁将无法保证任何特定访问顺序。与采用默认设置(使用不公平锁)相比,使用公平锁的程序在许多线程访问时表现为很低的总体吞吐量(即速度很慢,常常极其慢),但是在获得锁和保证锁分配的均衡性时差异较小。不过要注意的是,公平锁不能保证线程调度的公平性。因此,使用公平锁的众多线程中的一员可能获得多倍的成功机会,这种情况发生在其他活动线程没有被处理并且目前并未持有锁时。还要注意的是,未定时的 tryLock
方法并没有使用公平设置。因为即使其他线程正在等待,只要该锁是可用的,此方法就可以获得成功。
建议总是 立即实践,使用 lock
块来调用 try
,在之前/之后的构造中,最典型的代码如下:
class X {
private final ReentrantLock lock = new ReentrantLock();
// ...
public void m() {
lock.lock(); // block until condition holds
try {
// ... method body
} finally {
lock.unlock()
}
}
}
除了实现 Lock
接口,此类还定义了 isLocked
和 getLockQueueLength
方法,以及一些相关的 protected
访问方法,这些方法对检测和监视可能很有用。
该类的序列化与内置锁的行为方式相同:一个反序列化的锁处于解除锁定状态,不管它被序列化时的状态是怎样的。
此锁最多支持同一个线程发起的 2147483648 个递归锁。试图超过此限制会导致由锁方法抛出的 Error
。
二、构造方法
1、public ReentrantLock() 创建一个ReentrantLock
的实例。这等同于使用ReentrantLock(false)
。
2、public ReentrantLock(boolean fair) 创建一个具有给定公平策略的 ReentrantLock
。
参数:fair
- 如果此锁应该使用公平的排序策略,则该参数为 true
三、方法
1、public void lock() 获取锁。
如果该锁没有被另一个线程保持,则获取该锁并立即返回,将锁的保持计数设置为 1。
如果当前线程已经保持该锁,则将保持计数加 1,并且该方法立即返回。
如果该锁被另一个线程保持,则出于线程调度的目的,禁用当前线程,并且在获得锁之前,该线程将一直处于休眠状态,此时锁保持计数被设置为 1。
指定者:
接口 Lock
中的 lock
2、public void lockInterruptibly() throws InterruptedException 如果当前线程未被中断,则获取锁。
如果该锁没有被另一个线程保持,则获取该锁并立即返回,将锁的保持计数设置为 1。
如果当前线程已经保持此锁,则将保持计数加 1,并且该方法立即返回。
如果锁被另一个线程保持,则出于线程调度目的,禁用当前线程,并且在发生以下两种情况之一以前,该线程将一直处于休眠状态:
如果当前线程获得该锁,则将锁保持计数设置为 1。
如果当前线程:
则抛出 InterruptedException
,并且清除当前线程的已中断状态。
在此实现中,因为此方法是一个显式中断点,所以要优先考虑响应中断,而不是响应锁的普通获取或重入获取。
指定者:
接口 Lock
中的 lockInterruptibly
抛出:
InterruptedException
- 如果当前线程已中断。
3、public boolean tryLock() 仅在调用时锁未被另一个线程保持的情况下,才获取该锁。
如果该锁没有被另一个线程保持,并且立即返回 true
值,则将锁的保持计数设置为 1。即使已将此锁设置为使用公平排序策略,但是调用 tryLock()
仍将 立即获取锁(如果有可用的),而不管其他线程当前是否正在等待该锁。在某些情况下,此“闯入”行为可能很有用,即使它会打破公平性也如此。如果希望遵守此锁的公平设置,则使用 tryLock(0, TimeUnit.SECONDS)
,它几乎是等效的(也检测中断)。
如果当前线程已经保持此锁,则将保持计数加 1,该方法将返回 true
。
如果锁被另一个线程保持,则此方法将立即返回 false
值。
指定者:
接口 Lock
中的 tryLock
返回:
如果锁是自由的并且被当前线程获取,或者当前线程已经保持该锁,则返回 true
;否则返回 false
4、public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException 如果锁在给定等待时间内没有被另一个线程保持,且当前线程未被中断,则获取该锁。
如果该锁没有被另一个线程保持,并且立即返回 true
值,则将锁的保持计数设置为 1。如果为了使用公平的排序策略,已经设置此锁,并且其他线程都在等待该锁,则不会 获取一个可用的锁。这与 tryLock()
方法相反。如果想使用一个允许闯入公平锁的定时 tryLock
,那么可以将定时形式和不定时形式组合在一起:
if (lock.tryLock() || lock.tryLock(timeout, unit) ) { ... }
如果当前线程已经保持此锁,则将保持计数加 1,该方法将返回 true
。
如果锁被另一个线程保持,则出于线程调度目的,禁用当前线程,并且在发生以下三种情况之一以前,该线程将一直处于休眠状态:
如果获得该锁,则返回 true
值,并将锁保持计数设置为 1。
如果当前线程:
则抛出 InterruptedException
,并且清除当前线程的已中断状态。
如果超出了指定的等待时间,则返回值为 false
。如果该时间小于等于 0,则此方法根本不会等待。
在此实现中,因为此方法是一个显式中断点,所以要优先考虑响应中断,而不是响应锁的普通获取或重入获取,或者报告所用的等待时间。
指定者:
接口 Lock
中的 tryLock
参数:
timeout
- 等待锁的时间
unit
- timeout 参数的时间单位
返回:
如果锁是自由的并且由当前线程获取,或者当前线程已经保持该锁,则返回 true
;如果在获取该锁之前已经到达等待时间,则返回 false
抛出:
InterruptedException
- 如果当前线程被中断
NullPointerException
- 如果时间单位为 null
5、public void unlock() 试图释放此锁。
如果当前线程是此锁所有者,则将保持计数减 1。如果保持计数现在为 0,则释放该锁。如果当前线程不是此锁的持有者,则抛出 IllegalMonitorStateException
。
指定者:
接口 Lock
中的 unlock
抛出:
IllegalMonitorStateException
- 如果当前线程没有保持此锁
6、public Condition newCondition() 返回用来与此 Lock
实例一起使用的 Condition
实例。
在使用内置监视器锁时,返回的 Condition
实例支持与 Object
的监视器方法(wait
、notify
和 notifyAll
)相同的用法。
Condition
、waiting 或 signalling 这些方法中的任意一个方法时,如果没有保持此锁,则将抛出 IllegalMonitorStateException
。InterruptedException
,清除线程的中断状态。
指定者:
接口 Lock
中的 newCondition
返回:
Condition 对象
7、public int getHoldCount() 查询当前线程保持此锁的次数。
对于与解除锁操作不匹配的每个锁操作,线程都会保持一个锁。
保持计数信息通常只用于测试和调试。例如,如果不应该使用已经保持的锁进入代码的某一部分,则可以声明如下:
class X {
ReentrantLock lock = new ReentrantLock();
// ...
public void m() {
assert lock.getHoldCount() == 0;
lock.lock();
try {
// ... method body
} finally {
lock.unlock();
}
}
}
返回:
当前线程保持此锁的次数,如果此锁未被当前线程保持过,则返回 0
8、public boolean isHeldByCurrentThread() 查询当前线程是否保持此锁。
与内置监视器锁的 Thread.holdsLock(java.lang.Object)
方法类似,此方法通常用于调试和测试。例如,只在保持某个锁时才应调用的方法可以声明如下:
class X {
ReentrantLock lock = new ReentrantLock();
// ...
public void m() {
assert lock.isHeldByCurrentThread();
// ... method body
}
}
还可以用此方法来确保某个重入锁是否以非重入方式使用的,例如:
class X {
ReentrantLock lock = new ReentrantLock();
// ...
public void m() {
assert !lock.isHeldByCurrentThread();
lock.lock();
try {
// ... method body
} finally {
lock.unlock();
}
}
}
返回:
如果当前线程保持此锁,则返回 true
;否则返回 false
9、public boolean isLocked() 查询此锁是否由任意线程保持。此方法用于监视系统状态,不用于同步控制。
返回:如果任意线程保持此锁,则返回 true
;否则返回 false
10、
public final boolean isFair() 如果此锁的公平设置为 true,则返回 true
。
返回:如果此锁的公平设置为 true,则返回 true
11、
protected Thread getOwner() 返回目前拥有此锁的线程,如果此锁不被任何线程拥有,则返回 null
。
当此方法被不是拥有者的线程调用,返回值反映当前锁状态的最大近似值。例如,拥有者可以暂时为 null
,也就是说有些线程试图获取该锁,但还没有实现。此方法用于加快子类的构造速度,提供更多的锁监视设施。
返回:
拥有者,如果没有,则返回 null
12、public final boolean hasQueuedThreads() 查询是否有些线程正在等待获取此锁。注意,因为随时可能发生取消,所以返回 true
并不保证有其他线程将获取此锁。此方法主要用于监视系统状态。
返回:
如果可能有其他线程正在等待获取锁,则返回 true
13、public final boolean hasQueuedThread(Thread thread) 查询给定线程是否正在等待获取此锁。注意,因为随时可能发生取消,所以返回 true
并不保证此线程将获取此锁。此方法主要用于监视系统状态。
参数:
thread
- 线程
返回:
如果给定线程已加入队列并且正在等待此锁,则返回 true
抛出:
NullPointerException
- 如果 thread 为 null
14、public final int getQueueLength() 返回正等待获取此锁的线程估计数。该值仅是估计的数字,因为在此方法遍历内部数据结构的同时,线程的数目可能动态地变化。此方法用于监视系统状态,不用于同步控制。
返回:
正在等待此锁的线程估计数
15、protected Collection
因为在构造此结果的同时实际的线程 set 可能动态地变化,所以返回的 collection 仅是尽力的估计值。所返回 collection 中的元素没有特定的顺序。此方法用于加快子类的构造速度,以提供更多的监视设施。
返回:线程的 collection
16、public boolean hasWaiters(Condition condition) 查询是否有些线程正在等待与此锁有关的给定条件。
注意,因为随时可能发生超时和中断,所以返回 true
并不保证将来某个 signal
将唤醒线程。此方法主要用于监视系统状态。
参数:
condition
- 条件
返回:
如果有任何等待的线程,则返回 true
抛出:
IllegalMonitorStateException
- 如果没有保持此锁
IllegalArgumentException
- 如果给定 condition 与此锁无关
NullPointerException
- 如果 condition 为 null
17、public int getWaitQueueLength(Condition condition) 返回等待与此锁相关的给定条件的线程估计数。注意,因为随时可能发生超时和中断,所以只能将估计值作为实际等待线程数的上边界。此方法用于监视系统状态,不用于同步控制。
参数:
condition
- 条件
返回:
等待线程的估计数
抛出:
IllegalMonitorStateException
- 如果没有保持此锁
IllegalArgumentException
- 如果给定 condition 与此锁无关
NullPointerException
- 如果 condition 为 null
18、protected Collection
返回一个 collection,它包含可能正在等待与此锁相关给定条件的那些线程。因为在构造此结果的同时实际的线程 set 可能动态地变化,所以返回 collection 的元素只是尽力的估计值。所返回 collection 中的元素没有特定的顺序。此方法用于加快子类的构造速度,提供更多的条件监视设施。
参数:
condition
- 条件
返回:
线程的 collection
抛出:
IllegalMonitorStateException
- 如果没有保持此锁
IllegalArgumentException
- 如果给定 condition 与此锁无关
NullPointerException
- 如果 condition 为 null
19、public String toString() 返回标识此锁及其锁定状态的字符串。该状态括在括号中,它包括字符串 "Unlocked"
或字符串 "Locked by"
,后跟拥有线程的名称。
覆盖:
类 Object
中的 toString
返回:
标识此锁及其锁定状态的字符串。