ReentrantLock实现了lock接口,通过调用AbstractQueuedSynchronizer (AQS) 中的方法,实现了主要功能。
相关类图:
java.util.concurrent.locks.ReentrantLock 源码:
package java.util.concurrent.locks;
import java.util.concurrent.TimeUnit;
import java.util.Collection;
public class ReentrantLock implements Lock, java.io.Serializable {
private static final long serialVersionUID = 7373984872572414699L;
private final Sync sync;
abstract static class Sync extends AbstractQueuedSynchronizer {
//序列号
private static final long serialVersionUID = -5179523762034025860L;
//获取锁方法,交由NonfairSync和FairSync实现
abstract void lock();
// 非公平方式获取锁,用于tryLock()方法
final boolean nonfairTryAcquire(int acquires) {
//当前线程
final Thread current = Thread.currentThread();
// 继承至AbstractQueuedSynchronizer的方法
int c = getState();//获取锁状态值
//没有线程正在竞争该锁
if (c == 0) {
// 继承至AbstractQueuedSynchronizer的方法
if (compareAndSetState(0, acquires)) {//若state为0则将state修改为acquires的值,状态0表示锁没有被占用
//AbstractQueuedSynchronizer继承至AbstractOwnableSynchronizer的方法
setExclusiveOwnerThread(current);// 设置当前线程独占
return true;// 成功
}
}
else if (current == getExclusiveOwnerThread()) {// 当前线程拥有该锁
int nextc = c + acquires;// 增加重入次数
if (nextc < 0) // overflow(计数值小于0,则抛出异常)
throw new Error("Maximum lock count exceeded");
// 继承至AbstractQueuedSynchronizer的方法
setState(nextc);//设置锁状态值
return true;// 成功
}
return false;// 失败
}
// 试图在共享模式下获取对象状态,此方法应该查询是否允许它在共享模式下获取对象状态,如果允许,则获取它
protected final boolean tryRelease(int releases) {
int c = getState() - releases;
if (Thread.currentThread() != getExclusiveOwnerThread()) // 当前线程不为独占线程
throw new IllegalMonitorStateException(); // 抛出异常
// 释放标识
boolean free = false;
if (c == 0) {
free = true;
// 已经释放,清空独占
setExclusiveOwnerThread(null);
}
// 设置标识
setState(c);
return free;
}
// 判断资源是否被当前线程占有
protected final boolean isHeldExclusively() {
//AbstractQueuedSynchronizer继承至AbstractOwnableSynchronizer的方法
return getExclusiveOwnerThread() == Thread.currentThread();//判断占用资源的线程和当前线程是否一致
}
//新增一个条件队列
final ConditionObject newCondition() {
return new ConditionObject();
}
//返回资源的占用线程对象
final Thread getOwner() {
return getState() == 0 ? null : getExclusiveOwnerThread();
}
//得到锁状态值
final int getHoldCount() {
return isHeldExclusively() ? getState() : 0;//若资源被当前线程占用,返回状态值;否则返回0.
}
//判断资源是否被占用
final boolean isLocked() {
return getState() != 0;
}
//自定义反序列化逻辑
private void readObject(java.io.ObjectInputStream s)
throws java.io.IOException, ClassNotFoundException {
s.defaultReadObject();
setState(0); // 重置为未锁定状态
}
}
//非公平策略获取锁(每一次尝试获取锁,都不会按照公平等待的原则,让等待时间最久的线程获得锁。)
static final class NonfairSync extends Sync {
// 版本号
private static final long serialVersionUID = 7316153563782823691L;
// 实现获得锁的方法
final void lock() {
if (compareAndSetState(0, 1))//若state为0则将state修改为acquires的值,状态0表示锁没有被占用
// 把当前线程设置独占锁
setExclusiveOwnerThread(Thread.currentThread());
else//锁已经被占用,或者set失败
//以独占模式获取对象,忽略中断
acquire(1);
}
//尝试获取锁
protected final boolean tryAcquire(int acquires) {
//调用继承至Sync的方法
return nonfairTryAcquire(acquires);//非公平方式获取锁
}
}
//公平策略获取锁
static final class FairSync extends Sync {
//版本序列化
private static final long serialVersionUID = -3000897897090466540L;
// 实现获得锁的方法
final void lock() {
acquire(1);// 以独占模式获取对象,忽略中断
}
//尝试公平获取锁
protected final boolean tryAcquire(int acquires) {
// 获取当前线程
final Thread current = Thread.currentThread();
// 获取锁的状态值
int c = getState();
if (c == 0) {//没有线程正在竞争该锁
if (!hasQueuedPredecessors() &&
compareAndSetState(0, acquires)) { //等待线程队列未空并且 state为0且将state设置为acquires的值 成功
// 设置当前线程独占
setExclusiveOwnerThread(current);
return true;//成功
}
}
else if (current == getExclusiveOwnerThread()) {// 当前线程拥有该锁
int nextc = c + acquires;// 增加重入次数
if (nextc < 0) // overflow(计数值小于0,则抛出异常)
throw new Error("Maximum lock count exceeded");
// 设置状态
setState(nextc);
return true;//成功
}
return false;//失败
}
}
//默认非公平策略
public ReentrantLock() {
sync = new NonfairSync();
}
//传递参数确定采用公平策略或者是非公平策略,参数为true表示公平策略,否则,采用非公平策略
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
//获取锁
public void lock() {
sync.lock();
}
//如果当前线程未被中断,则获取锁
public void lockInterruptibly() throws InterruptedException {
sync.acquireInterruptibly(1);//直接调用AbstractQueuedSynchronizer的方法
}
//仅在调用时锁未被另一个线程保持的情况下,才获取该锁
public boolean tryLock() {
return sync.nonfairTryAcquire(1);//非公平获取锁
}
//如果锁在给定等待时间内没有被另一个线程保持,且当前线程未被中断,则获取该锁
public boolean tryLock(long timeout, TimeUnit unit)
throws InterruptedException {
return sync.tryAcquireNanos(1, unit.toNanos(timeout));//直接调用AbstractQueuedSynchronizer的方法
}
//试图释放此锁
public void unlock() {
sync.release(1);//直接调用AbstractQueuedSynchronizer的方法
}
//新增一个条件队列
public Condition newCondition() {
return sync.newCondition();//调用sync的方法
}
//查询当前线程保持此锁的次数
public int getHoldCount() {
return sync.getHoldCount();//调用sync的方法
}
//查询当前线程是否保持此锁
public boolean isHeldByCurrentThread() {
return sync.isHeldExclusively();//调用sync的方法
}
//查询此锁是否由某一线程保持着
public boolean isLocked() {
return sync.isLocked();//调用sync的方法
}
//查询当前对象是否为公平锁对象实例
public final boolean isFair() {
return sync instanceof FairSync;
}
//得到锁的当前持有线程对象
protected Thread getOwner() {
return sync.getOwner();
}
//查询是否存在线程正在等待获取此锁
public final boolean hasQueuedThreads() {
return sync.hasQueuedThreads();//调用AbstractQueuedSynchronizer的方法
}
//查询某一线程是否正在等待获取此锁
public final boolean hasQueuedThread(Thread thread) {
return sync.isQueued(thread);//调用AbstractQueuedSynchronizer的方法
}
//返回正等待获取此锁的线程估计数
public final int getQueueLength() {
return sync.getQueueLength();//调用AbstractQueuedSynchronizer的方法
}
//返回一个collection,它包含可能正等待获取此锁的线程
protected Collection<Thread> getQueuedThreads() {
return sync.getQueuedThreads();//调用AbstractQueuedSynchronizer的方法
}
//查询是否存在线程正在等待与此锁有关的给定条件
public boolean hasWaiters(Condition condition) {
if (condition == null)//条件对象为null,抛出空指针异常错误
throw new NullPointerException();
if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))//判断对象类型
throw new IllegalArgumentException("not owner");
return sync.hasWaiters((AbstractQueuedSynchronizer.ConditionObject)condition);//调用AbstractQueuedSynchronizer的方法
}
//返回等待与此锁相关的给定条件的相关线程的估计数
public int getWaitQueueLength(Condition condition) {
if (condition == null)//条件对象为null,抛出空指针异常错误
throw new NullPointerException();
if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))//判断对象类型
throw new IllegalArgumentException("not owner");
return sync.getWaitQueueLength((AbstractQueuedSynchronizer.ConditionObject)condition);//调用AbstractQueuedSynchronizer的方法
}
//返回一个collection,它包含可能正在等待与此锁相关给定条件的那些线程
protected Collection<Thread> getWaitingThreads(Condition condition) {
if (condition == null)//条件对象为null,抛出空指针异常错误
throw new NullPointerException();
if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))//判断对象类型
throw new IllegalArgumentException("not owner");
return sync.getWaitingThreads((AbstractQueuedSynchronizer.ConditionObject)condition);//调用AbstractQueuedSynchronizer的方法
}
//返回标识此锁及其锁定状态的字符串
public String toString() {
Thread o = sync.getOwner();//得到持有锁的线程实例
return super.toString() + ((o == null) ?
"[Unlocked]" :
"[Locked by thread " + o.getName() + "]");
}
}
类 ReentrantLock
public class ReentrantLock extends Object implements Lock, Serializable
已实现的接口:
Serializable, Lock
一个可重入的互斥锁 Lock
,它具有与使用 synchronized
方法和语句所访问的隐式监视器锁相同的一些基本行为和语义,但功能更强大。
此类的构造方法接受一个可选的 公平 参数。
- 当设置为 true 时,在多个线程的争用下,线程将按照它们发出请求的顺序来获得锁。
- 当设置为 false 时,只要线程在新发出请求的同时,该锁状态变为可用,那么线程将跳过队列中其他的等待线程并获得这个锁。
在公平的锁中,如果有其他线程持有这个锁或者有其他线程在队列中等待这个锁,那么新发出请求的线程将被放入队列中;在不公平的锁中,只有当锁被其他的线程持有时,新发出请求的线程才会被放入队列中。
与采用默认设置(使用不公平锁)相比,使用公平锁的程序,由于维护公平性而在挂起线程和恢复线程上增加了额外的开销,从而在许多线程访问时表现为很低的总体吞吐量(即速度很慢,常常极其慢),但是在获得锁和保证锁分配的均衡性时差异较小。在大多数情况下,非公平锁的性能要高于公平锁。
需要注意的是,未定时的 tryLock
方法并没有使用公平设置。因此即使其他线程正在等待,只要该锁是可用的,此方法就可以获得成功。
最典型的调用代码如下:
class X { private final ReentrantLock lock = new ReentrantLock(); // ... public void m() { lock.lock(); // block until condition holds try { // ... method body } finally { lock.unlock() } } }
该类的序列化与内置锁的行为方式相同:一个反序列化的锁处于解除锁定状态,不管它被序列化时的状态是怎样的。
此锁最多支持同一个线程发起的 2147483648 个递归锁。试图超过此限制会导致由锁方法抛出的 Error
。
构造方法摘要
ReentrantLock() 创建一个 ReentrantLock 的实例。 |
ReentrantLock(boolean fair) 创建一个具有给定公平策略的 ReentrantLock 。 |
ReentrantLock总共有三个内部类,并且三个内部类是紧密相关的,下面先看三个类的关系。
说明:ReentrantLock类内部总共存在Sync、NonfairSync、FairSync三个类,NonfairSync与FairSync类继承自Sync类,Sync类继承自AbstractQueuedSynchronizer抽象类。
NonfairSync:每一次都尝试获取锁,而并不会按照公平等待的原则进行等待,让等待时间最久的线程获得锁。
FairSync:当资源空闲时,它总是会先判断sync队列(AbstractQueuedSynchronizer中的数据结构)是否有等待时间更长的线程,如果存在,则将该线程加入到等待队列的尾部,实现了公平获取原则。
可以看出 FairSync 只要资源被其他线程占用,该线程就会添加到sync queue中的尾部,而不会先尝试获取资源。这也是和 Nonfair 最大的区别,Nonfair 每一次都会尝试去获取资源,如果此时该资源恰好被释放,则会被当前线程获取,这就造成了不公平的现象,当获取不成功,再加入队列尾部。
方法摘要
int | getHoldCount() 查询当前线程保持此锁的次数。 |
protected Thread | getOwner() 返回目前拥有此锁的线程,如果此锁不被任何线程拥有,则返回 null 。 |
protected Collection<Thread> | getQueuedThreads() 返回一个 collection,它包含可能正等待获取此锁的线程。 |
int | getQueueLength() 返回正等待获取此锁的线程估计数。 |
protected Collection<Thread> | getWaitingThreads(Condition condition) 返回一个 collection,它包含可能正在等待与此锁相关给定条件的那些线程。 |
int | getWaitQueueLength(Condition condition) 返回等待与此锁相关的给定条件的线程估计数。 |
boolean | hasQueuedThread(Thread thread) 查询给定线程是否正在等待获取此锁。 |
boolean | hasQueuedThreads() 查询是否有些线程正在等待获取此锁。 |
boolean | hasWaiters(Condition condition) 查询是否有些线程正在等待与此锁有关的给定条件。 |
boolean | isFair() 如果此锁的公平设置为 true,则返回 true 。 |
boolean | isHeldByCurrentThread() 查询当前线程是否保持此锁。 |
boolean | isLocked() 查询此锁是否由任意线程保持。 |
void | lock() 获取锁。 |
void | lockInterruptibly() 如果当前线程未被中断,则获取锁。 |
Condition | newCondition() 返回用来与此 Lock 实例一起使用的 Condition 实例。 |
String | toString() 返回标识此锁及其锁定状态的字符串。 |
boolean | tryLock() 仅在调用时锁未被另一个线程保持的情况下,才获取该锁。 |
boolean | tryLock(long timeout, TimeUnit unit) 如果锁在给定等待时间内没有被另一个线程保持,且当前线程未被中断,则获取该锁。 |
void | unlock() 试图释放此锁。 |
从类 java.lang.Object 继承的方法: clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait
ReentrantLock
public ReentrantLock()
创建一个 ReentrantLock
的实例。这等同于使用 ReentrantLock(false)
。
ReentrantLock
public ReentrantLock(boolean fair)
创建一个具有给定公平策略的 ReentrantLock
。
参数: fair
- 如果此锁应该使用公平的排序策略,则该参数为 true
lock
public void lock()
获取锁。
如果该锁没有被另一个线程保持,则获取该锁并立即返回,将锁的保持计数设置为 1。
如果当前线程已经保持该锁,则将保持计数加 1,并且该方法立即返回。
如果该锁被另一个线程保持,则出于线程调度的目的,禁用当前线程,并且在获得锁之前,该线程将一直处于休眠状态,此时锁保持计数被设置为 1。
lockInterruptibly
public void lockInterruptibly() throws InterruptedException
如果当前线程未被 中断,则获取锁。
如果该锁没有被另一个线程保持,则获取该锁并立即返回,将锁的保持计数设置为 1。
如果当前线程已经保持此锁,则将保持计数加 1,并且该方法立即返回。
如果锁被另一个线程保持,则出于线程调度目的,禁用当前线程,并且在发生以下两种情况之一以前,该线程将一直处于休眠状态:
- 锁由当前线程获得;或者
- 其他某个线程中断当前线程。
如果当前线程获得该锁,则将锁保持计数设置为 1。
如果当前线程:
- 在进入此方法时已经设置了该线程的中断状态;或者
- 在等待获取锁的同时被中断。
则抛出 InterruptedException
,并且清除当前线程的已中断状态。
在此实现中,因为此方法是一个显式中断点,所以要优先考虑响应中断,而不是响应锁的普通获取或重入获取。
抛出: InterruptedException
- 如果当前线程已中断。
tryLock
public boolean tryLock()
仅在调用时锁未被另一个线程保持的情况下,才获取该锁。
如果该锁没有被另一个线程保持,并且立即返回 true
值,则将锁的保持计数设置为 1。即使已将此锁设置为使用公平排序策略,但是调用 tryLock()
仍将 立即获取锁(如果有可用的),而不管其他线程当前是否正在等待该锁。在某些情况下,此“闯入”行为可能很有用,即使它会打破公平性也如此。如果希望遵守此锁的公平设置,则使用 tryLock(0, TimeUnit.SECONDS)
,它几乎是等效的(也检测中断)。
如果当前线程已经保持此锁,则将保持计数加 1,该方法将返回 true
。
如果锁被另一个线程保持,则此方法将立即返回 false
值。
返回:
如果锁是自由的并且被当前线程获取,或者当前线程已经保持该锁,则返回 true
;否则返回 false
tryLock
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,则此方法根本不会等待。
在此实现中,因为此方法是一个显式中断点,所以要优先考虑响应中断,而不是响应锁的普通获取或重入获取,或者报告所用的等待时间。
参数: timeout
- 等待锁的时间 unit
- timeout 参数的时间单位
返回:
如果锁是自由的并且由当前线程获取,或者当前线程已经保持该锁,则返回 true
;如果在获取该锁之前已经到达等待时间,则返回 false
抛出: InterruptedException
- 如果当前线程被中断 NullPointerException
- 如果时间单位为 null
unlock
public void unlock()
试图释放此锁。
如果当前线程是此锁所有者,则将保持计数减 1。如果保持计数现在为 0,则释放该锁。如果当前线程不是此锁的持有者,则抛出 IllegalMonitorStateException
。
抛出: IllegalMonitorStateException
- 如果当前线程没有保持此锁
newCondition
public Condition newCondition()
返回用来与此 Lock
实例一起使用的 Condition
实例。
在使用内置监视器锁时,返回的 Condition
实例支持与 Object
的监视器方法(wait
、notify
和 notifyAll
)相同的用法。
- 在调用
Condition
、waiting 或 signalling 这些方法中的任意一个方法时,如果没有保持此锁,则将抛出IllegalMonitorStateException
。 - 在调用 waiting 条件方法时,将释放锁,并在这些方法返回之前,重新获取该锁,将锁保持计数恢复为调用方法时所持有的值。
- 如果线程在等待时被中断,则等待将终止,并将抛出
InterruptedException
,清除线程的中断状态。 - 等待线程按 FIFO 顺序收到信号。
- 等待方法返回的线程重新获取锁的顺序与线程最初获取锁的顺序相同,在默认情况下,未指定此顺序,但对于公平 锁,它们更倾向于那些等待时间最长的线程。
返回:
Condition 对象
getHoldCount
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
isHeldByCurrentThread
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
isLocked
public boolean isLocked()
查询此锁是否由任意线程保持。此方法用于监视系统状态,不用于同步控制。
返回:
如果任意线程保持此锁,则返回 true
;否则返回 false
isFair
public final boolean isFair()
如果此锁的公平设置为 true,则返回 true
。
返回:
如果此锁的公平设置为 true,则返回 true
getOwner
protected Thread getOwner()
返回目前拥有此锁的线程,如果此锁不被任何线程拥有,则返回 null
。当此方法被不是拥有者的线程调用,返回值反映当前锁状态的最大近似值。 例如,拥有者可以暂时为 null
,也就是说有些线程试图获取该锁,但还没有实现。此方法用于加快子类的构造速度,提供更多的锁监视设施。
返回:
拥有者,如果没有,则返回 null
hasQueuedThreads
public final boolean hasQueuedThreads()
查询是否有些线程正在等待获取此锁。注意,因为随时可能发生取消,所以返回 true
并不保证有其他线程将获取此锁。此方法主要用于监视系统状态。
返回:
如果可能有其他线程正在等待获取锁,则返回 true
hasQueuedThread
public final boolean hasQueuedThread(Thread thread)
查询给定线程是否正在等待获取此锁。注意,因为随时可能发生取消,所以返回 true
并不保证此线程将获取此锁。此方法主要用于监视系统状态。
参数: thread
- 线程
返回:
如果给定线程已加入队列并且正在等待此锁,则返回 true
抛出: NullPointerException
- 如果 thread 为 null
getQueueLength
public final int getQueueLength()
返回正等待获取此锁的线程估计数。该值仅是估计的数字,因为在此方法遍历内部数据结构的同时,线程的数目可能动态地变化。此方法用于监视系统状态,不用于同步控制。
返回:
正在等待此锁的线程估计数
getQueuedThreads
protected Collection<Thread> getQueuedThreads()
返回一个 collection,它包含可能正等待获取此锁的线程。因为在构造此结果的同时实际的线程 set 可能动态地变化,所以返回的 collection 仅是尽力的估计值。所返回 collection 中的元素没有特定的顺序。此方法用于加快子类的构造速度,以提供更多的监视设施。
返回:
线程的 collection
hasWaiters
public boolean hasWaiters(Condition condition)
查询是否有些线程正在等待与此锁有关的给定条件。注意,因为随时可能发生超时和中断,所以返回 true
并不保证将来某个 signal
将唤醒线程。此方法主要用于监视系统状态。
参数: condition
- 条件
返回:
如果有任何等待的线程,则返回 true
抛出: IllegalMonitorStateException
- 如果没有保持此锁 IllegalArgumentException
- 如果给定 condition 与此锁无关 NullPointerException
- 如果 condition 为 null
getWaitQueueLength
public int getWaitQueueLength(Condition condition)
返回等待与此锁相关的给定条件的线程估计数。注意,因为随时可能发生超时和中断,所以只能将估计值作为实际等待线程数的上边界。此方法用于监视系统状态,不用于同步控制。
参数: condition
- 条件
返回:
等待线程的估计数
抛出: IllegalMonitorStateException
- 如果没有保持此锁 IllegalArgumentException
- 如果给定 condition 与此锁无关 NullPointerException
- 如果 condition 为 null
getWaitingThreads
protected Collection<Thread> getWaitingThreads(Condition condition)
返回一个 collection,它包含可能正在等待与此锁相关给定条件的那些线程。因为在构造此结果的同时实际的线程 set 可能动态地变化,所以返回 collection 的元素只是尽力的估计值。所返回 collection 中的元素没有特定的顺序。此方法用于加快子类的构造速度,提供更多的条件监视设施。
参数: condition
- 条件
返回:
线程的 collection
抛出: IllegalMonitorStateException
- 如果没有保持此锁 IllegalArgumentException
- 如果给定 condition 与此锁无关 NullPointerException
- 如果 condition 为 null
toString
public String toString()
返回标识此锁及其锁定状态的字符串。该状态括在括号中,它包括字符串 "Unlocked"
或字符串 "Locked by"
,后跟拥有线程的 名称。
覆盖:
类 Object
中的 toString
返回:
标识此锁及其锁定状态的字符串。
公平锁和非公平锁使用示例:
注意:如果线程持有锁的时间过长,则当所有线程都发送获取的请求完毕,则无法体现出公平锁和非公平锁的差异(发送请求的线程且恰好锁也未被其他线程所持有,公平锁优先考虑等待队列的第一个线程,非公平锁则不考虑)
公平锁:
package com.thread;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class FairSyncDemo implements Runnable {
Lock lock;
FairSyncDemo(boolean isFair) {
lock = new ReentrantLock(isFair);
}
@Override
public void run() {
System.out.println("我是线程:" + Thread.currentThread().getName());
lock.lock();
try {
System.out.println("线程:" + Thread.currentThread().getName() + "获取到锁..");
} finally {
System.out.println("线程:" + Thread.currentThread().getName() + "即将释放锁..");
System.out.println("------------------------");
lock.unlock();
}
}
public static void main(String[] args) {
FairSyncDemo fairSyncDemo = new FairSyncDemo(true);
for (int i = 1; i <= 20; i++) {
new Thread(fairSyncDemo).start();
}
}
}
运行结果:
我是线程:Thread-0
我是线程:Thread-4
线程:Thread-0获取到锁..
线程:Thread-0即将释放锁..
------------------------
我是线程:Thread-3
我是线程:Thread-2
我是线程:Thread-1
我是线程:Thread-7
我是线程:Thread-6
我是线程:Thread-5
我是线程:Thread-9
我是线程:Thread-8
线程:Thread-4获取到锁..
线程:Thread-4即将释放锁..
------------------------
线程:Thread-3获取到锁..
线程:Thread-3即将释放锁..
------------------------
线程:Thread-2获取到锁..
线程:Thread-2即将释放锁..
------------------------
线程:Thread-1获取到锁..
线程:Thread-1即将释放锁..
------------------------
线程:Thread-7获取到锁..
线程:Thread-7即将释放锁..
------------------------
线程:Thread-6获取到锁..
线程:Thread-6即将释放锁..
------------------------
线程:Thread-5获取到锁..
线程:Thread-5即将释放锁..
------------------------
线程:Thread-9获取到锁..
线程:Thread-9即将释放锁..
------------------------
线程:Thread-8获取到锁..
线程:Thread-8即将释放锁..
------------------------
可以发现,线程获取锁的顺序于它们各自start的顺序一致。而且只要上一个线程释放了锁,下一个线程才能获取得到锁。
不公平锁:
package com.thread;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class FairSyncDemo implements Runnable {
Lock lock;
FairSyncDemo(boolean isFair) {
lock = new ReentrantLock(isFair);
}
@Override
public void run() {
System.out.println("我是线程:" + Thread.currentThread().getName());
try {
lock.lock();
System.out.println("线程:" + Thread.currentThread().getName() + "获取到锁..");
} finally {
System.out.println("线程:" + Thread.currentThread().getName() + "即将释放锁..");
System.out.println("------------------------");
lock.unlock();
}
}
public static void main(String[] args) {
FairSyncDemo fairSyncDemo = new FairSyncDemo(false);
for (int i = 1; i <= 10; i++) {
new Thread(fairSyncDemo).start();
}
}
}
将main()方法,创建FairSyncDemo实例的构造方法参数改为 false.
运行结果:
我是线程:Thread-0
我是线程:Thread-4
我是线程:Thread-3
我是线程:Thread-1
我是线程:Thread-6
我是线程:Thread-2
线程:Thread-0获取到锁..
线程:Thread-0即将释放锁..
------------------------
我是线程:Thread-5
线程:Thread-3获取到锁..
线程:Thread-3即将释放锁..
------------------------
线程:Thread-4获取到锁..
线程:Thread-4即将释放锁..
------------------------
线程:Thread-1获取到锁..
线程:Thread-1即将释放锁..
------------------------
我是线程:Thread-9
我是线程:Thread-8
我是线程:Thread-7
线程:Thread-6获取到锁..
线程:Thread-6即将释放锁..
------------------------
线程:Thread-2获取到锁..
线程:Thread-2即将释放锁..
------------------------
线程:Thread-5获取到锁..
线程:Thread-5即将释放锁..
------------------------
线程:Thread-9获取到锁..
线程:Thread-9即将释放锁..
------------------------
线程:Thread-8获取到锁..
线程:Thread-8即将释放锁..
------------------------
线程:Thread-7获取到锁..
线程:Thread-7即将释放锁..
------------------------
需要注意,即使是创建的公平锁,调用tryLock() 则同样是不公平的。
package com.thread;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class FairSyncDemo implements Runnable {
Lock lock;
FairSyncDemo(boolean isFair) {
lock = new ReentrantLock(isFair);
}
@Override
public void run() {
System.out.println("我是线程:" + Thread.currentThread().getName());
boolean flag = true;
try {
flag = lock.tryLock();
System.out.println("线程:" + Thread.currentThread().getName() + "获取到锁..");
} finally {
System.out.println("线程:" + Thread.currentThread().getName() + "即将释放锁..");
System.out.println("------------------------");
if (flag)
lock.unlock();
}
}
public static void main(String[] args) {
FairSyncDemo fairSyncDemo = new FairSyncDemo(true);
for (int i = 1; i <= 10; i++) {
new Thread(fairSyncDemo).start();
}
}
}
运行结果:
我是线程:Thread-0
我是线程:Thread-4
线程:Thread-4获取到锁..
我是线程:Thread-3
我是线程:Thread-1
我是线程:Thread-7
线程:Thread-3获取到锁..
线程:Thread-3即将释放锁..
------------------------
我是线程:Thread-6
线程:Thread-4即将释放锁..
------------------------
我是线程:Thread-2
线程:Thread-2获取到锁..
线程:Thread-2即将释放锁..
------------------------
线程:Thread-0获取到锁..
线程:Thread-0即将释放锁..
------------------------
我是线程:Thread-5
线程:Thread-6获取到锁..
线程:Thread-6即将释放锁..
------------------------
线程:Thread-7获取到锁..
线程:Thread-7即将释放锁..
------------------------
我是线程:Thread-9
线程:Thread-9获取到锁..
线程:Thread-9即将释放锁..
------------------------
我是线程:Thread-8
线程:Thread-8获取到锁..
线程:Thread-8即将释放锁..
------------------------
线程:Thread-1获取到锁..
线程:Thread-5获取到锁..
线程:Thread-5即将释放锁..
------------------------
线程:Thread-1即将释放锁..
------------------------