/**
* 一个可重入的互斥锁 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。
*/
public class ReentrantLock implements Lock, java.io.Serializable {
private static final long serialVersionUID = 7373984872572414699L;
/**
* 提供所有实现机制的同步器
*/
private final Sync sync;
/**
* 这个锁的同步控制基础。
* 下面再细分为公平和非公平版本。
* 使用AQS状态表示锁上的持有数。
*/
abstract static class Sync extends AbstractQueuedSynchronizer {
private static final long serialVersionUID = -5179523762034025860L;
/**
* 执行Lock.Lock。
* 子类化的主要原因是允许非公平版本的快速路径。
*/
abstract void lock();
/**
* 执行不公平的tryLock。
* tryAcquire是在子类中实现的,但两者都需要对trylock方法进行不公平的尝试。
*/
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState(); // 获取同步状态的当前值
if (c == 0) {
if (compareAndSetState(0, acquires)) { // CAS判断
setExclusiveOwnerThread(current); // 设置current为当前拥有独占访问的线程
return true;
}
}
else if (current == getExclusiveOwnerThread()) { // 如果当前线程是setExclusiveOwnerThread 最后设置的线程
int nextc = c + acquires;
if (nextc < 0) // overflow
throw new Error("Maximum lock count exceeded");
setState(nextc); // 设置同步状态的值为nextc
return true;
}
return false;
}
/**
* 试图设置状态来反映独占模式下的一个释放。
* @param releases release 参数。该值总是传递给 release 方法的那个值,
* 或者是因某个条件等待而保存在条目上的当前状态值。该值是不间断的,并且可以表示任何内容。
* @return 如果此对象现在处于完全释放状态,从而使等待的线程都可以试图获得此对象,则返回 true;否则返回 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); // 设置null为当前拥有独占访问的线程
}
setState(c); // 设置同步状态的值为c
return free;
}
/**
* 如果对于当前(正调用的)线程,同步是以独占方式进行的,则返回 true。
* @return 如果同步是以独占方式进行的,则返回true;其他情况则返回 false
*/
protected final boolean isHeldExclusively() {
// 虽然我们通常必须在owner之前读取状态,但是我们不需要这样做来检查当前线程是否是owner
return getExclusiveOwnerThread() == Thread.currentThread();
}
final ConditionObject newCondition() {
return new ConditionObject();
}
// 方法从外部类传递
/**
* 获取当前线程
* @return 当前线程
*/
final Thread getOwner() {
return getState() == 0 ? null : getExclusiveOwnerThread();
}
final int getHoldCount() {
return isHeldExclusively() ? getState() : 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)) // 设置当前线程为当前拥有独占访问的线程
setExclusiveOwnerThread(Thread.currentThread());
else // 以独占模式获取对象,忽略中断
acquire(1);
}
/**
* 试图在独占模式下获取对象状态。
* @param acquires acquire 参数。该值总是传递给 acquire 方法的那个值,或者是因某个条件等待而保存在条目上的值。
* 该值是不间断的,并且可以表示任何内容。
* @return 如果成功,则返回 true。在成功的时候,此对象已经被获取。
*/
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
}
/**
* 同步对象的公平锁
*/
static final class FairSync extends Sync {
private static final long serialVersionUID = -3000897897090466540L;
final void lock() {
acquire(1);
}
/**
* 公平版的tryAcquire.
* 不要授予访问权限,除非递归调用或没有等待者或第一个。
*/
protected final boolean tryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
if (!hasQueuedPredecessors() &&
compareAndSetState(0, acquires)) {// 设置current为当前拥有独占访问的线程
setExclusiveOwnerThread(current);
return true;
}
}
else if (current == getExclusiveOwnerThread()) {// 如果当前线程是setExclusiveOwnerThread 最后设置的线程
int nextc = c + acquires;
if (nextc < 0)
throw new Error("Maximum lock count exceeded");
setState(nextc);// 设置同步状态的值为nextc
return true;
}
return false;
}
}
/**
* 创建一个 ReentrantLock 的实例。这等同于使用 ReentrantLock(false)。
*/
public ReentrantLock() {
sync = new NonfairSync();
}
/**
* 创建一个具有给定公平策略的 ReentrantLock。
* @param fair 如果此锁应该使用公平的排序策略,则该参数为 true
*/
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
/**
* 获取锁。
* 如果该锁没有被另一个线程保持,则获取该锁并立即返回,将锁的保持计数设置为 1。
* 如果当前线程已经保持该锁,则将保持计数加 1,并且该方法立即返回。
* 如果该锁被另一个线程保持,则出于线程调度的目的,禁用当前线程,并且在获得锁之前,该线程将一直处于休眠状态,此时锁保持计数被设置为 1。
* 覆盖:接口Lock中的lock
*/
public void lock() {
sync.lock();
}
/**
* 如果当前线程未被中断,则获取锁。
* 如果该锁没有被另一个线程保持,则获取该锁并立即返回,将锁的保持计数设置为 1。
* 如果当前线程已经保持此锁,则将保持计数加 1,并且该方法立即返回。
* 如果锁被另一个线程保持,则出于线程调度目的,禁用当前线程,并且在发生以下两种情况之一以前,该线程将一直处于休眠状态:
* 锁由当前线程获得;或者
* 其他某个线程中断当前线程。
* 如果当前线程获得该锁,则将锁保持计数设置为 1。
* 如果当前线程:
* 在进入此方法时已经设置了该线程的中断状态;或者
* 在等待获取锁的同时被中断。
* 则抛出 InterruptedException,并且清除当前线程的已中断状态。
* 在此实现中,因为此方法是一个显式中断点,所以要优先考虑响应中断,而不是响应锁的普通获取或重入获取。
* 覆盖:接口Lock中的lockInterruptibly
*
* @throws InterruptedException 如果当前线程已中断。
*/
public void lockInterruptibly() throws InterruptedException {
sync.acquireInterruptibly(1);
}
/**
* 仅在调用时锁未被另一个线程保持的情况下,才获取该锁。
* 如果该锁没有被另一个线程保持,并且立即返回 true 值,则将锁的保持计数设置为 1。
* 即使已将此锁设置为使用公平排序策略,但是调用 tryLock() 仍将 立即获取锁(如果有可用的),而不管其他线程当前是否正在等待该锁。
* 在某些情况下,此“闯入”行为可能很有用,即使它会打破公平性也如此。
* 如果希望遵守此锁的公平设置,则使用 tryLock(0, TimeUnit.SECONDS) ,它几乎是等效的(也检测中断)。
* 如果当前线程已经保持此锁,则将保持计数加 1,该方法将返回 true。
* 如果锁被另一个线程保持,则此方法将立即返回 false 值。
* 覆盖:接口Lock中的tryLock
*
* @return 如果锁是自由的并且被当前线程获取,或者当前线程已经保持该锁,则返回 true;否则返回 false
*/
public boolean tryLock() {
return sync.nonfairTryAcquire(1);
}
/**
* 如果锁在给定等待时间内没有被另一个线程保持,且当前线程未被中断,则获取该锁。
* 如果该锁没有被另一个线程保持,并且立即返回 true 值,则将锁的保持计数设置为 1。
* 如果为了使用公平的排序策略,已经设置此锁,并且其他线程都在等待该锁,则不会 获取一个可用的锁。
* 这与 tryLock() 方法相反。如果想使用一个允许闯入公平锁的定时 tryLock,那么可以将定时形式和不定时形式组合在一起:
* if (lock.tryLock() || lock.tryLock(timeout, unit) ) { ... }
* 如果当前线程已经保持此锁,则将保持计数加 1,该方法将返回 true。
* 如果锁被另一个线程保持,则出于线程调度目的,禁用当前线程,并且在发生以下三种情况之一以前,该线程将一直处于休眠状态:
* 锁由当前线程获得;或者
* 其他某个线程中断 当前线程;或者
* 已超过指定的等待时间
* 如果获得该锁,则返回 true 值,并将锁保持计数设置为 1。
*
* 如果当前线程:
* 在进入此方法时已经设置了该线程的中断状态;或者
* 在等待获取锁的同时被中断。
* 则抛出 InterruptedException,并且清除当前线程的已中断状态。
* 如果超出了指定的等待时间,则返回值为 false。如果该时间小于等于 0,则此方法根本不会等待。
* 在此实现中,因为此方法是一个显式中断点,所以要优先考虑响应中断,而不是响应锁的普通获取或重入获取,或者报告所用的等待时间。
* 覆盖:接口Lock中的tryLock
*
* @param timeout 等待锁的时间
* @param unit timeout 参数的时间单位
* @return 如果锁是自由的并且由当前线程获取,或者当前线程已经保持该锁,则返回 true;
* 如果在获取该锁之前已经到达等待时间,则返回 false
* @throws InterruptedException 如果当前线程被中断
*/
public boolean tryLock(long timeout, TimeUnit unit)
throws InterruptedException {
return sync.tryAcquireNanos(1, unit.toNanos(timeout));
}
/**
* 试图释放此锁。
* 如果当前线程是此锁所有者,则将保持计数减 1。如果保持计数现在为 0,则释放该锁。
* 如果当前线程不是此锁的持有者,则抛出 IllegalMonitorStateException。
* 覆盖:接口Lock中的unlock
*/
public void unlock() {
sync.release(1);
}
/**
* 返回用来与此 Lock 实例一起使用的 Condition 实例。
* 在使用内置监视器锁时,返回的 Condition 实例支持与 Object 的监视器方法(wait、notify 和 notifyAll)相同的用法。
* 在调用 Condition、waiting 或 signalling 这些方法中的任意一个方法时,如果没有保持此锁,则将抛出 IllegalMonitorStateException。
* 在调用 waiting 条件方法时,将释放锁,并在这些方法返回之前,重新获取该锁,将锁保持计数恢复为调用方法时所持有的值。
* 如果线程在等待时被中断,则等待将终止,并将抛出 InterruptedException,清除线程的中断状态。
* 等待线程按 FIFO 顺序收到信号。
* 等待方法返回的线程重新获取锁的顺序与线程最初获取锁的顺序相同,在默认情况下,未指定此顺序,但对于公平 锁,它们更倾向于那些等待时间最长的线程。
* 覆盖:接口Lock中的newCondition
*
* @return Condition 对象
*/
public Condition newCondition() {
return sync.newCondition();
}
/**
* 查询当前线程保持此锁的次数。
* 对于与解除锁操作不匹配的每个锁操作,线程都会保持一个锁。
* 保持计数信息通常只用于测试和调试。例如,如果不应该使用已经保持的锁进入代码的某一部分,则可以声明如下:
* class X {
* ReentrantLock lock = new ReentrantLock();
* // ...
* public void m() {
* assert lock.getHoldCount() == 0;
* lock.lock();
* try {
* // ... method body
* } finally {
* lock.unlock();
* }
* }
* }
* @return 当前线程保持此锁的次数,如果此锁未被当前线程保持过,则返回 0
*/
public int getHoldCount() {
return sync.getHoldCount();
}
/**
* 查询当前线程是否保持此锁。
* 与内置监视器锁的 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();
* }
* }
* }
* @return 如果当前线程保持此锁,则返回 true;否则返回 false
*/
public boolean isHeldByCurrentThread() {
return sync.isHeldExclusively();
}
/**
* 查询此锁是否由任意线程保持。此方法用于监视系统状态,不用于同步控制。
* @return 如果任意线程保持此锁,则返回 true;否则返回 false
*/
public boolean isLocked() {
return sync.isLocked();
}
/**
* 如果此锁的公平设置为 true,则返回 true。
* @return 如果此锁的公平设置为 true,则返回 true
*/
public final boolean isFair() {
return sync instanceof FairSync;
}
/**
* 返回目前拥有此锁的线程,如果此锁不被任何线程拥有,则返回 null。
* 当此方法被不是拥有者的线程调用,返回值反映当前锁状态的最大近似值。
* 例如,拥有者可以暂时为 null,也就是说有些线程试图获取该锁,但还没有实现。
* 此方法用于加快子类的构造速度,提供更多的锁监视设施。
* @return 拥有者,如果没有,则返回 null
*/
protected Thread getOwner() {
return sync.getOwner();
}
/**
* 查询是否有些线程正在等待获取此锁。
* 注意,因为随时可能发生取消,所以返回 true 并不保证有其他线程将获取此锁。此方法主要用于监视系统状态。
* @return 如果可能有其他线程正在等待获取锁,则返回 true
*/
public final boolean hasQueuedThreads() {
return sync.hasQueuedThreads();
}
/**
* 查询给定线程是否正在等待获取此锁。
* 注意,因为随时可能发生取消,所以返回 true 并不保证此线程将获取此锁。此方法主要用于监视系统状态。
* @param thread 线程
* @return 如果给定线程已加入队列并且正在等待此锁,则返回 true
*/
public final boolean hasQueuedThread(Thread thread) {
return sync.isQueued(thread);
}
/**
* 返回正等待获取此锁的线程估计数。
* 该值仅是估计的数字,因为在此方法遍历内部数据结构的同时,线程的数目可能动态地变化。此方法用于监视系统状态,不用于同步控制。
* @return 正在等待此锁的线程估计数
*/
public final int getQueueLength() {
return sync.getQueueLength();
}
/**
* 返回一个 collection,它包含可能正等待获取此锁的线程。
* 因为在构造此结果的同时实际的线程 set 可能动态地变化,所以返回的 collection 仅是尽力的估计值。
* 所返回 collection 中的元素没有特定的顺序。此方法用于加快子类的构造速度,以提供更多的监视设施。
* @return 线程的 collection
*/
protected Collection<Thread> getQueuedThreads() {
return sync.getQueuedThreads();
}
/**
* 查询是否有些线程正在等待与此锁有关的给定条件。
* 注意,因为随时可能发生超时和中断,所以返回 true 并不保证将来某个 signal 将唤醒线程。此方法主要用于监视系统状态。
* @param condition 条件
* @return 如果有任何等待的线程,则返回 true
*/
public boolean hasWaiters(Condition condition) {
if (condition == null) // 如果 condition 为 null
throw new NullPointerException();
if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))
throw new IllegalArgumentException("not owner"); // 如果给定 condition 与此锁无关
return sync.hasWaiters((AbstractQueuedSynchronizer.ConditionObject)condition);
}
/**
* 返回等待与此锁相关的给定条件的线程估计数。
* 注意,因为随时可能发生超时和中断,所以只能将估计值作为实际等待线程数的上边界。此方法用于监视系统状态,不用于同步控制。
* @param condition 条件
* @return 等待线程的估计数
*/
public int getWaitQueueLength(Condition condition) {
if (condition == null) // 如果 condition 为 null
throw new NullPointerException();
if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))
throw new IllegalArgumentException("not owner"); // 如果给定 condition 与此锁无关
return sync.getWaitQueueLength((AbstractQueuedSynchronizer.ConditionObject)condition);
}
/**
* 返回一个 collection,它包含可能正在等待与此锁相关给定条件的那些线程。
* 因为在构造此结果的同时实际的线程 set 可能动态地变化,所以返回 collection 的元素只是尽力的估计值。
* 所返回 collection 中的元素没有特定的顺序。此方法用于加快子类的构造速度,提供更多的条件监视设施。
* @param condition 条件
* @return 线程的 collection
*/
protected Collection<Thread> getWaitingThreads(Condition condition) {
if (condition == null) // 如果 condition 为 null
throw new NullPointerException();
if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))
throw new IllegalArgumentException("not owner"); // 如果给定 condition 与此锁无关
return sync.getWaitingThreads((AbstractQueuedSynchronizer.ConditionObject)condition);
}
/**
* 返回标识此锁及其锁定状态的字符串。
* 该状态括在括号中,它包括字符串 "Unlocked" 或字符串 "Locked by",后跟拥有线程的名称。
* 覆盖:Object中的toString
* @return 标识此锁及其锁定状态的字符串。
*/
public String toString() {
Thread o = sync.getOwner();
return super.toString() + ((o == null) ?
"[Unlocked]" :
"[Locked by thread " + o.getName() + "]");
}
}
ReentrantLock源码分析。
猜你喜欢
转载自blog.csdn.net/en_joker/article/details/104378519
今日推荐
周排行