ReentrantLock 源码解析
ReentrantLock 源码解析
ReentrantLock 类描述
一种可重入互斥锁 Lock ,与使用 synchronized 方法和语句访问的隐式监控锁具有相同的基本行为和语义,但具有扩展的功能。
-
一个 ReentrantLock 被上次成功锁住但还没有解锁的线程拥有,当锁不属于其他线程时,调用 lock() 的线程将成功地获取锁返回。如果当前线程已经拥有锁,该方法将立即返回。这可以通过方法 isHeldByCurrentThread() 和 getHoldCount() 来检查。
-
这个类的构造函数接受一个可选参数
fairness
。当设置 true 时,在争用的情况下,锁有利于授予访问等待时间最长的线程的访问权。否则,此锁不能保证任何特定的访问顺序。使用由多个线程访问的公平锁的程序可能显示出较低的总体吞吐量(即,较慢;通常比使用默认设置的慢得多),但获得锁的时间差异较小,并保证不会出现“饥饿”现象。但是要注意,锁的公平性并不保证线程调度的公平性。。因此,使用公平锁的多个线程中的一个可以连续多次获得该锁,而其他活动线程目前没有在进行操作,也没有持有该锁。还要注意,不定时的 tryLock() 方法不遵守公平性设置。如果锁可用,即使其他线程正在等待,它也会成功。
-
建议在调用 lock() 后总是紧跟 try 块,最典型的是在before - after结构中,例如:
class X { private final ReentrantLock lock = new ReentrantLock(); // ... public void m() { lock.lock(); // block until condition holds try { // ... method body } finally { lock.unlock() } } }
-
除了实现 Lock() 接口之外,这个类还定义了 public 和 protected 两个方法,用于检查锁的状态。其中一些方法只对检测和监控有用。
-
这个类的序列化与内置锁的行为相同:反序列化的锁处于未锁定状态,无论序列化时的状态如何。
-
同一个线程最多支持2147483647个递归锁。如果超过这个限制,锁定方法会抛出 Error 。
ReentrantLock 源码
public class ReentrantLock implements Lock, Serializable {
private static final long serialVersionUID = 7373984872572414699L;
/** Synchronizer providing all implementation mechanics */
private final Sync sync;
/**
* 此锁的同步控制基础。分为以下公平和非公平版本。使用AQS状态表示锁的保持数。
*/
abstract static class Sync extends AbstractQueuedSynchronizer {
private static final long serialVersionUID = -5179523762034025860L;
abstract void lock();
/**
* 非公平,尝试获取锁(现场时获取锁,获取失败进入队列)
*/
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
// c=0 表示当前锁未被其他线程持有
if (c == 0) {
// 直接尝试获取锁,获取成功,返回 (公平锁则是,先判断等待队列中是否存在等待的线程)
if (compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
//线程重入的情况
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0) // overflow
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
//获取锁失败 false
return false;
}
/**
* 释放锁:(返回是否完全释放锁了的)
* 如果当前线程是此锁的持有者,那么将减少持有者计数。
* 如果保持计数现在为零,则解除锁定。
* 如果当前线程不是此锁的持有者,则抛出{@link IllegalMonitorStateException}。
*/
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);
}
//锁重入的情况下,释放锁,只是 state - 1
setState(c);
return free;
}
/**
* 判断当前线程是否是持有锁的线程
*/
protected final boolean isHeldExclusively() {
return getExclusiveOwnerThread() == Thread.currentThread();
}
final ConditionObject newCondition() {
return new ConditionObject();
}
// ========================= 从外部类传递的方法 =============================
// Methods relayed from outer class
/**
* 获取锁的持有线程
*/
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); // reset to unlocked state
}
}
/**
* 非公平锁的同步对象
*/
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);//获取锁失败,进入等待队列
}
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();
// c=0 表示当前锁未被其他线程持有
if (c == 0) {
//判断等待队列的为空,为空则尝试设置值,获取锁
if (!hasQueuedPredecessors() &&
compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
// current = getExclusiveOwnerThread() 表示 锁重入,state + 1
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0)
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
// 获取锁失败,后续根据 false 值,进入等待队列
return false;
}
}
/**
* 无参构造(默认非公平锁)
*/
public ReentrantLock() {
sync = new NonfairSync();
}
/**
* 根据参数判断 构建:公平(true)或非公平锁(false)
*/
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
/**
* 获取锁。
* 如果锁没有被其他线程持有,则获取锁并立即返回,将锁持有计数设置为 1。
* 如果当前线程已经持有锁,那么持有计数加1,该方法立即返回。
* 如果锁被另一个线程持有,那么当前线程将无法进行线程调度,并处于休眠状态,直到获得锁,此时锁保持计数设置为1。
*/
public void lock() {
sync.lock();
}
/**
* 除非当前线程是 interrupted,否则获取锁。
* 1.如果另一个线程未持有锁,则获取该锁并立即返回,将锁持有计数设置为1。
* 2.如果当前线程已经持有该锁,则持有计数将增加1,方法将立即返回。
* 3.如果锁由另一个线程持有,则当前线程出于线程调度目的而被禁用,并处于休眠状态,直到发生以下两种情况之一:锁由当前线程获取 或 其他线程中断当前线程。
* 4.如果当前线程获取了锁,则锁保持计数设置为1。
* 5.如果当前线程:在进入该方法时设置其中断状态;或在获取锁时被中断。则抛出{@link InterruptedException},并清除当前线程的中断状态
* 在这个实现中,由于该方法是一个显式中断点,因此优先考虑响应中断,而不是正常或可重入获取锁。
*/
public void lockInterruptibly() throws InterruptedException {
sync.acquireInterruptibly(1);
}
/**
* 尝试获取锁
* 仅当锁在调用时没有被另一个线程持有时,才获取锁。
* 1.如果锁没有被其他线程持有,则获取锁,并立即返回值为 true ,将锁持有次数设置为1。 即使该锁被设置为使用公平排序策略,如果锁可用,调用 tryLock() 将立即获得锁,无论其他线程是否正在等待该锁。
* 这个 barging; 行为在某些情况下是有用的,即使它破坏了公平。如果您想遵守此锁的公平性设置,则使用 tryLock(long, TimeUnit) tryLock(0, TimeUnit. seconds),这几乎是等效的(它还检测中断)。
* 2.如果当前线程已经持有此锁,则持有计数将增加1,方法返回 true
* 3.如果锁由另一个线程持有,则此方法将立即返回值 false。
*/
public boolean tryLock() {
return sync.nonfairTryAcquire(1);
}
/**
* 给定时间内尝试获取锁,获取是否成功,都需要返回获取锁的情况
*/
public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException {
return sync.tryAcquireNanos(1, unit.toNanos(timeout));
}
/**
* 释放锁
*
* 如果当前线程是此锁的持有者,那么将减少持有者计数。
* 如果保持计数现在为零,则解除锁定。
* 如果当前线程不是此锁的持有者,则抛出{@link IllegalMonitorStateException}。
*/
public void unlock() {
sync.release(1);
}
/**
* 创建一个 等待条件
*/
public Condition newCondition() {
return sync.newCondition();
}
/**
* 查询当前线程对此锁的保留数。
*/
public int getHoldCount() {
return sync.getHoldCount();
}
/**
* 查询当前线程是否持有此锁。
*/
public boolean isHeldByCurrentThread() {
return sync.isHeldExclusively();
}
/**
* 查询此锁是否由任何线程持有。该方法设计用于监控系统状态,而不是用于同步控制。
*/
public boolean isLocked() {
return sync.isLocked();
}
/**
* 判断是否是公平锁
*/
public final boolean isFair() {
return sync instanceof FairSync;
}
/**
* 返回当前持有锁的线程
*/
protected Thread getOwner() {
return sync.getOwner();
}
/**
* 判断等待队列是否为空
*/
public final boolean hasQueuedThreads() {
return sync.hasQueuedThreads();
}
/**
* 判断当前等待队列中是否包含 某一个线程
*/
public final boolean hasQueuedThread(Thread thread) {
return sync.isQueued(thread);
}
/**
* 获取等待队列的长度
*/
public final int getQueueLength() {
return sync.getQueueLength();
}
/**
* 获取等待队列中的所有线程
*/
protected Collection<Thread> getQueuedThreads() {
return sync.getQueuedThreads();
}
/**
* 判断是否有 等待某一个条件 的线程
*/
public boolean hasWaiters(Condition condition) {
if (condition == null)
throw new NullPointerException();
if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))
throw new IllegalArgumentException("not owner");
return sync.hasWaiters((AbstractQueuedSynchronizer.ConditionObject)condition);
}
/**
* 获取等待 某个条件的 等待队列长度
*/
public int getWaitQueueLength(Condition condition) {
if (condition == null)
throw new NullPointerException();
if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))
throw new IllegalArgumentException("not owner");
return sync.getWaitQueueLength((AbstractQueuedSynchronizer.ConditionObject)condition);
}
/**
* 获取等待 某一个条件的 所有线程
*/
protected Collection<Thread> getWaitingThreads(Condition condition) {
if (condition == null)
throw new NullPointerException();
if (!(condition instanceof AbstractQueuedSynchronizer.ConditionObject))
throw new IllegalArgumentException("not owner");
return sync.getWaitingThreads((AbstractQueuedSynchronizer.ConditionObject)condition);
}
/**
* Returns a string identifying this lock, as well as its lock state.
* The state, in brackets, includes either the String {@code "Unlocked"}
* or the String {@code "Locked by"} followed by the
* {@linkplain Thread#getName name} of the owning thread.
*
* @return a string identifying this lock, as well as its lock state
*/
public String toString() {
Thread o = sync.getOwner();
return super.toString() + ((o == null) ?
"[Unlocked]" :
"[Locked by thread " + o.getName() + "]");
}
}