ReentrantLock 是 Java.util.concurrent 中的一个可重入互斥锁,它通过 AQS(AbstractQueuedSynchronizer)实现了同步操作,支持公平锁和非公平锁两种机制。
整体UML架构
构造函数
支持公平锁和非公平锁,默认非公平锁
public ReentrantLock() {
sync = new NonfairSync();
}
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
获取锁
着重讲述lock
lock()
public void lock() {
sync.lock();
}
此处公平锁和非公平锁由不同的实现
非公平锁实现
final void lock() {
// 设置同步状态
if (compareAndSetState(0, 1))
//设置独占状态线程
setExclusiveOwnerThread(Thread.currentThread());
else
//状态设置失败,已经被其他线程或者当前线程获取
acquire(1);
}
//AQS方法
protected final void setExclusiveOwnerThread(Thread thread) {
exclusiveOwnerThread = thread;
}
acquire()
用于获取锁并阻塞线程,直到获取锁成功
public final void acquire(int arg) {
// 1.尝试获取锁
if (!tryAcquire(arg) &&
//2.获取锁失败,将构造独占Node并加入等待队列
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
//3.如果中断,再次设置中断标记
selfInterrupt();
}
tryAcquire(arg)
是AQS提供的API方法,在NonfairSync
中实现如下
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
//Sync方法
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
//未被占用
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;
}
//其他线程占用
return false;
}
addWaiter
前期已经贴出,具体可参考juejin.cn/post/724320…
final boolean acquireQueued(final Node node, int arg)
是独占方式获取锁,与共享模式获取锁类似doAcquireSharedInterruptibly
final boolean acquireQueued(final Node node, int arg) {
boolean failed = true;
try {
boolean interrupted = false;
for (;;) {
final Node p = node.predecessor();
//前驱节点是头结点,尝试获取状态state
if (p == head && tryAcquire(arg)) {
setHead(node);
p.next = null; // help GC
failed = false;
return interrupted;
}
//不是头结点或者头结点获取失败处理
if (shouldParkAfterFailedAcquire(p, node) &&
//当前线程park并判断是否中断
parkAndCheckInterrupt())
interrupted = true;
}
} finally {
if (failed)
//失败释放等待队列中Node节点
cancelAcquire(node);
}
}
shouldParkAfterFailedAcquire
parkAndCheckInterrupt
cancelAcquire
前期已经贴出,具体可参考juejin.cn/post/724320…
selfInterrupt
如果在acquireQueued中已经中断,需要重新设置中断标记,因为Thread.interrupted()
是会清除中断标记的
static void selfInterrupt() {
Thread.currentThread().interrupt();
}
公平锁实现
在FairSync中
final void lock() {
acquire(1);
}
acquire
和上述分公平锁实现一致,其中tryAcquire
实现不一致
protected final boolean tryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
if (!hasQueuedPredecessors() &&
compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
else if (current == getExclusiveOwnerThread()) {
int nextc = c + acquires;
if (nextc < 0)
throw new Error("Maximum lock count exceeded");
setState(nextc);
return true;
}
return false;
}
public final boolean hasQueuedPredecessors() {
Node t = tail; // Read fields in reverse initialization order
Node h = head;
Node s;
return h != t &&
((s = h.next) == null || s.thread != Thread.currentThread());
}
其他获取锁方法
中断获取锁public void lockInterruptibly() throws InterruptedException
public void lockInterruptibly() throws InterruptedException {
sync.acquireInterruptibly(1);
}
public final void acquireInterruptibly(int arg)
throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
if (!tryAcquire(arg))
doAcquireInterruptibly(arg);
}
private void doAcquireInterruptibly(int arg)
throws InterruptedException {
final Node node = addWaiter(Node.EXCLUSIVE);
boolean failed = true;
try {
for (;;) {
final Node p = node.predecessor();
if (p == head && tryAcquire(arg)) {
setHead(node);
p.next = null; // help GC
failed = false;
return;
}
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
//此处和非中断获取锁不一样
throw new InterruptedException();
}
} finally {
if (failed)
cancelAcquire(node);
}
}
尝试获取锁public boolean tryLock()
public boolean tryLock() {
return sync.nonfairTryAcquire(1);
}
nonfairTryAcquire上文已经提出实现
尝试获取锁(一定时间,可中断)public boolean tryLock(long timeout, TimeUnit unit) throws InterruptedException
public boolean tryLock(long timeout, TimeUnit unit)
throws InterruptedException {
return sync.tryAcquireNanos(1, unit.toNanos(timeout));
}
public final boolean tryAcquireNanos(int arg, long nanosTimeout)
throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
return tryAcquire(arg) ||
//次数实现不一致
doAcquireNanos(arg, nanosTimeout);
}
private boolean doAcquireNanos(int arg, long nanosTimeout)
throws InterruptedException {
if (nanosTimeout <= 0L)
return false;
final long deadline = System.nanoTime() + nanosTimeout;
final Node node = addWaiter(Node.EXCLUSIVE);
boolean failed = true;
try {
for (;;) {
final Node p = node.predecessor();
if (p == head && tryAcquire(arg)) {
setHead(node);
p.next = null; // help GC
failed = false;
return true;
}
nanosTimeout = deadline - System.nanoTime();
//超时未获取到,返回
if (nanosTimeout <= 0L)
return false;
if (shouldParkAfterFailedAcquire(p, node) &&
nanosTimeout > spinForTimeoutThreshold)
LockSupport.parkNanos(this, nanosTimeout);
// 中断
if (Thread.interrupted())
throw new InterruptedException();
}
} finally {
if (failed)
cancelAcquire(node);
}
}
解锁
public void unlock() {
sync.release(1);
}
public final boolean release(int arg) {
if (tryRelease(arg)) {
Node h = head;
if (h != null && h.waitStatus != 0)
//唤醒后继节点
unparkSuccessor(h);
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;
//可重入锁全部释放,将独占锁线程置为null
setExclusiveOwnerThread(null);
}
setState(c);
return free;
}
条件队列
AQS的条件队列在 juejin.cn/post/724304… 中已有描述 本次主要对Condition接口方法进行源码解析,主要是等待和唤醒两类
public interface Condition {
void await() throws InterruptedException;
void awaitUninterruptibly();
long awaitNanos(long nanosTimeout) throws InterruptedException;
boolean await(long time, TimeUnit unit) throws InterruptedException;
boolean awaitUntil(Date deadline) throws InterruptedException;
void signal();
void signalAll();
}
等待
await()
//AQS的ConditionObject
public final void await() throws InterruptedException {
//检查当前线程是否被中断,如果被中断,则抛出 InterruptedException 异常
if (Thread.interrupted())
throw new InterruptedException();
//1.当前线程加入条件等待队列中,创建一个新的 Node.CONDITION(条件等待模式)节点,并将其加入条件等待队列的尾部
Node node = addConditionWaiter();
//2.完全释放当前线程持有的锁。该方法会释放当前线程持有的所有锁,而不仅仅是 Condition 相关的锁
int savedState = fullyRelease(node);
int interruptMode = 0;
//3.进入循环,检查当前线程是否被加入到同步队列中,如果没有,则调用 LockSupport.park(this) 方法阻塞当前线程,等待其他线程唤醒
while (!isOnSyncQueue(node)) {
//当其他线程调用 signal() 或 signalAll() 方法唤醒当前线程时,当前线程会重新竞争锁,如果获取到了锁,则继续执行
LockSupport.park(this);
// 检查当前线程是否被中断,如果被中断,则返回中断模式
if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
break;
}
// 重新将当前线程加入同步队列中,等待重新获取锁
if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
interruptMode = REINTERRUPT;
if (node.nextWaiter != null) // clean up if cancelled
//清除已经被取消的节点
unlinkCancelledWaiters();
if (interruptMode != 0)
//通过中断标记做后续处理
reportInterruptAfterWait(interruptMode);
}
addConditionWaiter
构造一个Node节点,并加入到队列尾部
private Node addConditionWaiter() {
Node t = lastWaiter;
// If lastWaiter is cancelled, clean out.
if (t != null && t.waitStatus != Node.CONDITION) {
//从头节点开始清除CANCLED节点
unlinkCancelledWaiters();
t = lastWaiter;
}
Node node = new Node(Thread.currentThread(), Node.CONDITION);
if (t == null)
firstWaiter = node;
else
t.nextWaiter = node;
lastWaiter = node;
return node;
}
private void unlinkCancelledWaiters() {
Node t = firstWaiter;
Node trail = null;
while (t != null) {
Node next = t.nextWaiter;
if (t.waitStatus != Node.CONDITION) {
t.nextWaiter = null;
if (trail == null)
firstWaiter = next;
else
trail.nextWaiter = next;
if (next == null)
lastWaiter = trail;
}
else
trail = t;
t = next;
}
}
fullyRelease
释放当前线程state,唤醒其他节点
final int fullyRelease(Node node) {
boolean failed = true;
try {
int savedState = getState();
if (release(savedState)) {
failed = false;
return savedState;
} else {
throw new IllegalMonitorStateException();
}
} finally {
if (failed)
node.waitStatus = Node.CANCELLED;
}
}
public final boolean release(int arg) {
if (tryRelease(arg)) {
Node h = head;
if (h != null && h.waitStatus != 0)
unparkSuccessor(h);
return true;
}
return false;
}
isOnSyncQueue
用于检查指定节点是否在同步队列中,Condition中的队列是等待队列,AQS中的变种CHL是同步队列
final boolean isOnSyncQueue(Node node) {
if (node.waitStatus == Node.CONDITION || node.prev == null)
return false;
if (node.next != null) // If has successor, it must be on queue
return true;
return findNodeFromTail(node);
}
private boolean findNodeFromTail(Node node) {
Node t = tail;
for (;;) {
if (t == node)
return true;
if (t == null)
return false;
t = t.prev;
}
}
checkInterruptWhileWaiting
用于检查线程在等待过程中是否被中断
private int checkInterruptWhileWaiting(Node node) {
return Thread.interrupted() ?
//中断才执行
(transferAfterCancelledWait(node) ? THROW_IE : REINTERRUPT) :
0;
}
final boolean transferAfterCancelledWait(Node node) {
// 尝试将节点的 waitStatus 从 Node.CONDITION(表示节点在条件等待队列中)设置为 0(表示节点已经被取消)
if (compareAndSetWaitStatus(node, Node.CONDITION, 0)) {
//需要将节点重新加入同步队列中,以便其他线程能够重新竞争锁
enq(node);
return true;
}
//如果 compareAndSetWaitStatus(node, Node.CONDITION, 0) 方法返回 false,说明节点已经被其他线程
//取消或者已经被加入同步队列中,当前线程需要等待其他线程完成操作。因此,使用一个简单的自旋循环,不断
//地调用 isOnSyncQueue(node) 方法检查节点是否已经加入同步队列中。一旦节点被加入同步队列中,就退出循环并返回 false。
while (!isOnSyncQueue(node))
Thread.yield();
return false;
}
reportInterruptAfterWait
THROW_IE抛出异常 REINTERRUPT再次中断
private void reportInterruptAfterWait(int interruptMode)
throws InterruptedException {
if (interruptMode == THROW_IE)
throw new InterruptedException();
else if (interruptMode == REINTERRUPT)
selfInterrupt();
}
其他等待
public final long awaitNanos(long nanosTimeout) throws InterruptedException
public final long awaitNanos(long nanosTimeout)
throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
Node node = addConditionWaiter();
int savedState = fullyRelease(node);
final long deadline = System.nanoTime() + nanosTimeout;
int interruptMode = 0;
while (!isOnSyncQueue(node)) {
if (nanosTimeout <= 0L) {
//如果超时时间已经到期,则调用 transferAfterCancelledWait(Node node) 方法将当前节点转移到同步队列中
transferAfterCancelledWait(node);
break;
}
//时间很短,就不park,直接循环
if (nanosTimeout >= spinForTimeoutThreshold)
LockSupport.parkNanos(this, nanosTimeout);
if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
break;
nanosTimeout = deadline - System.nanoTime();
}
if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
interruptMode = REINTERRUPT;
if (node.nextWaiter != null)
unlinkCancelledWaiters();
if (interruptMode != 0)
reportInterruptAfterWait(interruptMode);
return deadline - System.nanoTime();
}
public final boolean awaitUntil(Date deadline) throws InterruptedException
public final boolean awaitUntil(Date deadline)
throws InterruptedException {
long abstime = deadline.getTime();
if (Thread.interrupted())
throw new InterruptedException();
Node node = addConditionWaiter();
int savedState = fullyRelease(node);
boolean timedout = false;
int interruptMode = 0;
while (!isOnSyncQueue(node)) {
if (System.currentTimeMillis() > abstime) {
timedout = transferAfterCancelledWait(node);
break;
}
LockSupport.parkUntil(this, abstime);
if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
break;
}
if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
interruptMode = REINTERRUPT;
if (node.nextWaiter != null)
unlinkCancelledWaiters();
if (interruptMode != 0)
reportInterruptAfterWait(interruptMode);
return !timedout;
}
public final boolean await(long time, TimeUnit unit) throws InterruptedException
public final boolean await(long time, TimeUnit unit)
throws InterruptedException {
long nanosTimeout = unit.toNanos(time);
if (Thread.interrupted())
throw new InterruptedException();
Node node = addConditionWaiter();
int savedState = fullyRelease(node);
final long deadline = System.nanoTime() + nanosTimeout;
boolean timedout = false;
int interruptMode = 0;
while (!isOnSyncQueue(node)) {
if (nanosTimeout <= 0L) {
timedout = transferAfterCancelledWait(node);
break;
}
if (nanosTimeout >= spinForTimeoutThreshold)
LockSupport.parkNanos(this, nanosTimeout);
if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
break;
nanosTimeout = deadline - System.nanoTime();
}
if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
interruptMode = REINTERRUPT;
if (node.nextWaiter != null)
unlinkCancelledWaiters();
if (interruptMode != 0)
reportInterruptAfterWait(interruptMode);
return !timedout;
}
public final void awaitUninterruptibly()
public final void awaitUninterruptibly() {
Node node = addConditionWaiter();
int savedState = fullyRelease(node);
boolean interrupted = false;
while (!isOnSyncQueue(node)) {
LockSupport.park(this);
if (Thread.interrupted())
interrupted = true;
}
if (acquireQueued(node, savedState) || interrupted)
selfInterrupt();
}
唤醒
单个唤醒
public final void signal() {
//不是当前线程持有锁,直接抛出异常
if (!isHeldExclusively())
throw new IllegalMonitorStateException();
Node first = firstWaiter;
if (first != null)
doSignal(first);
}
doSignal
用于唤醒等待队列中的第一个线程
private void doSignal(Node first) {
do {
if ( (firstWaiter = first.nextWaiter) == null)
lastWaiter = null;
first.nextWaiter = null;
//将第一个节点转移到同步队列中,并返回转移结果。如果转移成功,则返回 true;否则返回 false。
} while (!transferForSignal(first) &&
(first = firstWaiter) != null);
}
final boolean transferForSignal(Node node) {
if (!compareAndSetWaitStatus(node, Node.CONDITION, 0))
return false;
Node p = enq(node);
int ws = p.waitStatus;
if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL))
LockSupport.unpark(node.thread);
return true;
}
全部唤醒
public final void signalAll() {
if (!isHeldExclusively())
throw new IllegalMonitorStateException();
Node first = firstWaiter;
if (first != null)
doSignalAll(first);
}
private void doSignalAll(Node first) {
lastWaiter = firstWaiter = null;
do {
Node next = first.nextWaiter;
first.nextWaiter = null;
transferForSignal(first);
first = next;
} while (first != null);
}
JDK中实现AQS简介
同步工具 | 与AQS关联 | 详细介绍 |
---|---|---|
AQS原理讲解 | AQS原理介绍 | 并发-AQS原理讲解 |
ReentrantLock | 使用AQS保存锁重复持有的次数。当一个线程获取锁时,ReentrantLock记录当前获得锁的线程标识,用于检测是否重复获取,以及错误线程试图解锁操作时异常情况的处理。 | AQS之Reentrantlonk源码解读 |
Semaphore | 使用AQS同步状态来保存信号量的当前计数。tryRelease会增加计数,acquireShared会减少计数。 | Semaphore 源码分析以及AQS共享加解锁 |
CountDownLatch | 在多线程并发执行任务时,有时需要让某些线程等待某些条件达成后再开始执行,这时就可以使用CountDownLatch来实现 | CountDownLatch 源码分析 |
ThreadPoolExecutor | 创建线程池中的工作线程worker继承AQS,实现独占资源 | 参考 并发-AQS之ThreadPoolExecutor源码解读(一) |
CyclicBarrier | 多个线程等待彼此达到一个共同的屏障点,然后同时继续执行。 | 并发-AQS之CyclicBarrier源码解读 |
ReentrantReadWriteLock | 可重入读写锁,它允许多个线程同时读取一个共享资源,但只允许一个线程写入该共享资源。 | 参考 并发-AQS之ReentrantReadWriteLock源码解读(一) |