ReentrantLock 依赖关系如下图所示
非公平锁实现原理
ReentrantLock 默认采用非公平锁。
// ReentrantLock
public ReentrantLock() {
sync = new NonfairSync();
}
加锁流程
ReentrantLock 的 lock 方法通过同步器的 lock 方法实现。
// ReentrantLock
public void lock() {
sync.lock();
}
同步器的 lock 方法会先调用 initialTryLock() 方法,如果失败,则调用 acquire() 方法。
// Sync extends AbstractQueuedSynchronizer
final void lock() {
if (!initialTryLock())
acquire(1);
}
// AbstractQueuedSynchronizer
public final void acquire(int arg) {
// 尝试获取锁
if (!tryAcquire(arg))
// 获取锁失败则加入的等待队列
// null, 自定义参数, 非共享锁, 不可打断, 无时限, 时限
acquire(null, arg, false, false, false, 0L);
}
NonfairSync 的 initialTryLock 分两步:尝试获取锁、尝试重入。
NonfairSync 的 tryAcquire 方法被调用前,必定会调用 initialTryLock() 方法检查锁是否被当前线程持有,也即,调用 tryAcquire 方法时,锁必定未被当前线程持有。因此,当未有线程持有锁时,tryAcquire 才能尝试获取锁。
// NonfairSync extends Sync
static final class NonfairSync extends Sync {
// 初次尝试获取锁
final boolean initialTryLock() {
Thread current = Thread.currentThread();
// 通过CAS尝试获取锁
if (compareAndSetState(0, 1)) {
// 将锁的持有者设为当前线程
setExclusiveOwnerThread(current);
return true;
}
// 尝试获取锁失败,判断锁的持有者是否为当前线程
else if (getExclusiveOwnerThread() == current) {
// 锁重入
int c = getState() + 1;
// 整数溢出
if (c < 0)
throw new Error("Maximum lock count exceeded");
// 设置锁的状态:state 表示重入次数
setState(c);
return true;
} else
return false;
}
// 非初次尝试获取锁
protected final boolean tryAcquire(int acquires) {
// 未有线程持有锁时,当前线程尝试获取锁
if (getState() == 0 && compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(Thread.currentThread());
return true;
}
return false;
}
}
AbstractQueuedSynchronizer 的 acquire 方法负责将线程加入等待队列,acquire 方法的主要执行步骤如下:
若非第一个等待线程且前驱存在,则检查当前节点前驱是否已被取消(前驱线程被取消)
- 若已被取消,则需要从队尾开始,往前清理已取消的节点,进入下一轮循环。
- 若未被取消,检查当前线程是否已成为第一个线程,若是,则自旋等待,进入下一轮循环
- 若是第一个等待线程或者前驱不存在,则尝试获取锁,获取锁成功则直接返回 1 表示获取锁成功,
准备将当前线程加入等待队列
- 3.1 若等待队列未创建,则创建等待队列,进入下一轮循环
- 3.2 否则,若节点未创建,则创建节点,进入下一轮循环
- 3.3 否则,若节点信息未设置,则设置节点信息(包括将节点加入队尾),进入下一轮循环
- 3.4 否则,若为第一个等待线程且自旋次数不为 0,提示 JVM 当前线程正在忙等,进入下一轮循环
- 3.5 否则,若节点状态为 0(默认),则将节点状态设为 1(WAITING)
- 3.6 否则,重置自旋自旋次数,当前线程陷入等待,被唤醒后将等待状态置为 0。
// AbstractQueuedSynchronizer
final int acquire(
// 尝试获取锁的节点
Node node,
// 自定义参数
int arg,
// 是否为共享锁
boolean shared,
// 是否可打断
boolean interruptible,
// 是否带时限
boolean timed,
// 时限
long time
) {
Thread current = Thread.currentThread();
byte spins = 0, postSpins = 0;
boolean interrupted = false, first = false;
Node pred = null;
for (;;) {
// 检查前驱是否被取消
if (
// 非第一个等待线程
!first &&
// 前驱存在
// 除非本方法被ConditionNode.await()方法调用,否则node初始必为null
// 也即,此条件在第一轮循环必为false
(pred = (node == null) ? null : node.prev) != null &&
// 非第一个等待线程
!(first = (head == pred))
) {
if (pred.status < 0) {
// 若前驱被取消,则需要清理队列中取消的线程
// 此举是为确保给当前节点的前驱能唤醒当前节点
cleanQueue();
continue;
} else if (pred.prev == null) {
// 若前驱的前驱为null,说明当前线程是第一个线程
// !first 和 pred.prev == null 之间,head的值被修改,导致当前线程成为第一个线程
// 第一个线程自旋等待,以减少线程切换的开销
Thread.onSpinWait();
continue;
}
}
// 尝试获取锁
if (
// 第一个线程 或者 前驱不存在
first || pred == null
) {
boolean acquired;
// 尝试获取锁
try {
if (shared)
acquired = (tryAcquireShared(arg) >= 0);
else
acquired = tryAcquire(arg);
} catch (Throwable ex) {
cancelAcquire(node, interrupted, false);
throw ex;
}
// 获取锁成功
if (acquired) {
// 当前线程是第一个线程
if (first) {
node.prev = null;
head = node;
pred.next = null;
node.waiter = null;
if (shared)
// 共享节点获取到锁之后需要唤醒下一个节点
signalNextIfShared(node);
if (interrupted)
// 独占节点获取到锁之后需要重新设置打断标记
current.interrupt();
}
return 1;
}
}
// 尝试获取锁失败后,准备将线程加入等待队列
Node t;
if (
// 等待队列未创建
(t = tail) == null
) {
// 创建等待队列
if (tryInitializeHead() == null)
// 创建队列失败则调用tryAcquire尝试获取锁,失败则park(long)等待,重复
return acquireOnOOME(shared, arg);
} else if (
// 节点未创建:创建节点
node == null
) {
try {
// 创建节点
node = (shared) ? new SharedNode() : new ExclusiveNode();
} catch (OutOfMemoryError oome) {
// 创建节点失败则调用tryAcquire尝试获取锁,失败则park(long)等待,重复
return acquireOnOOME(shared, arg);
}
} else if (
// 前驱未设置:设置节点信息
pred == null
) {
// 当前节点线程
node.waiter = current;
// 当前节点前驱(节点将由前驱唤醒)
node.setPrevRelaxed(t);
// 通过CAS将尾节点置为当前节点
if (!casTail(t, node))
// 失败则进入下一次循环
node.setPrevRelaxed(null);
else
// 将当前节点加入队尾
// 此时t仍指向原来的尾节点,当前节点已为实际尾节点
t.next = node;
} else if (
// 第一个节点 自旋次数不为0
first && spins != 0
) {
// 自旋等待
--spins;
Thread.onSpinWait();
} else if (
// 当前节点状态为0(新建节点状态默认为0)
node.status == 0
) {
// 当前节点状态置为等待(WAITING=1)
node.status = WAITING;
} else {
// 到此处,节点已被创建,节点信息已被设置,节点状态已被设置
long nanos;
// 设置自旋次数
spins = postSpins = (byte)((postSpins << 1) | 1);
// 当前线程等待
if (!timed)
// 无时限等待
LockSupport.park(this);
else if ((nanos = time - System.nanoTime()) > 0L)
// 有时限等待
LockSupport.parkNanos(this, nanos);
else
// 等待超时
break;
// 线程被唤醒后,将状态设置为0
node.clearStatus();
// 被打断且可被打断
if ((interrupted |= Thread.interrupted()) && interruptible)
break;
}
}
// (等待超时)或者(被打断且可被打断)则取消获取锁
return cancelAcquire(node, interrupted, interruptible);
}
线程被唤醒后,再次尝试获取锁,若获取锁失败,不立即陷入等待,而是自旋,再次尝试获取锁,直到自旋次数耗尽。线程每次陷入等待前,会重置自旋次数,自旋次数为 2^k,其中,k 表示当前线程是第 k 陷入等待。注意,陷入等待是指执行 park() 方法,而不是指加入等待队列,加入等待队列的操作只会执行一次。
非公平体现在哪?先进先出不是公平的吗?阅读非公平同步器的 acquire() 源码可知,先将尝试获取锁,再将线程加入等待队列,也即,新来的线程可直接与等待队列中的线程竞争,准确地说,新来的线程可直接与等待队列中的第一个等待线程竞争,这导致新来的线程可能比等待队列中的线程先执行,这是不公平的。
检查线程是否被打断使用的是 Thread.interrupted() 方法,Thread.interrupted() 会清除打断标记,线程再次调用 LockSupport.park() 时仍能生效,Thread.isInterrupted() 不会清除打断标记,线程再次调用 LockSupport.park() 时无效。
如果线程(等待超时)或者(被打断且可被打断),则会取消尝试获取锁 cancelAcquire(),如果因为等待超时而导致取消尝试获取锁,则会保留打断标记。非公平同步器 NonfairSync 没有用到 cancelAcquire() 的返回值。
private int cancelAcquire(
Node node,
boolean interrupted,
boolean interruptible
) {
// 修改节点信息
if (node != null) {
node.waiter = null;
node.status = CANCELLED;
// 清理队列
if (node.prev != null)
cleanQueue();
}
if (interrupted) {
if (interruptible)
// CANCELLED=0x80000000,负数
return CANCELLED;
else
// 重新打断自己,将打断标记置为 true
Thread.currentThread().interrupt();
}
return 0;
}
解锁流程
ReentrantLock 的 unlock 方法通过同步器的 release方法实现。
// ReentrantLock
public void unlock() {
sync.release(1);
}
同步器的 release 方法会先调用 tryRelease 尝试释放锁,若释放成功则会唤醒下一个线程。
// AbstractQueuedSynchronizer
public final boolean release(int arg) {
if (tryRelease(arg)) {
signalNext(head);
return true;
}
return false;
}
同步器的 tryRelease 方法先修改锁的持有者(置为 null),再修改锁的状态。
// Sync extends AbstractQueuedSynchronizer
@ReservedStackAccess
protected final boolean tryRelease(int releases) {
int c = getState() - releases;
// 仅锁的持有者才可以释放锁
if (getExclusiveOwnerThread() != Thread.currentThread())
throw new IllegalMonitorStateException();
// free=true 表示现在重入次数为0
boolean free = (c == 0);
// 重入次数为0则将线程持有者置为null
if (free)
setExclusiveOwnerThread(null);
// 设置线程状态
setState(c);
return free;
}
同步器中的 signalNext 方法将等待队列中的第一个线程唤醒。
// AbstractQueuedSynchronizer
private static void signalNext(Node h) {
Node s;
if (h != null && (s = h.next) != null && s.status != 0) {
// 将state设置为 ~WAITING
s.getAndUnsetStatus(WAITING);
// 唤醒下一个线程(等待队列中的第一个等待线程)
LockSupport.unpark(s.waiter);
}
}
可重入
阅读 NonfairSync 的源码可以发现,线程第一次尝试获取锁时,尝试将 state 由 0 置为 1 失败后,会检查锁的持有者是否是自己,若是,则累计重入次数,并返回 true,表示获取锁成功。
当锁的持有者为当前线程,当前线程再次尝试获取锁仍能成功,此即可重入。
// NonfairSync extends Sync
static final class NonfairSync extends Sync {
// 初次尝试获取锁
final boolean initialTryLock() {
Thread current = Thread.currentThread();
// 通过CAS尝试获取锁
if (compareAndSetState(0, 1)) {
// 将锁的持有者设为当前线程
setExclusiveOwnerThread(current);
return true;
}
// 尝试获取锁失败,判断锁的持有者是否为当前线程
else if (getExclusiveOwnerThread() == current) {
// 锁重入
int c = getState() + 1;
// 整数溢出
if (c < 0)
throw new Error("Maximum lock count exceeded");
// 设置锁的状态:state 表示重入次数
setState(c);
return true;
} else
return false;
}
...
}
阅读 Sync 的源码可以发现,释放锁时,会将重入次数减去 releases(实际为 1),仅当重入次数为 0 时,线程才将锁的持有者置为 null 并返回 true,表示锁已成功释放。
// Sync extends AbstractQueuedSynchronizer
@ReservedStackAccess
protected final boolean tryRelease(int releases) {
int c = getState() - releases;
// 仅锁的持有者才可以释放锁
if (getExclusiveOwnerThread() != Thread.currentThread())
throw new IllegalMonitorStateException();
// free=true 表示现在重入次数为0
boolean free = (c == 0);
// 重入次数为0则将线程持有者置为null
if (free)
setExclusiveOwnerThread(null);
// 设置线程状态
setState(c);
return free;
}
可打断
理解一下参数 interruptible
- interruptible = true,获取锁的过程中允许被打断,立即响应打断,不再尝试获取锁。
- interruptible = false,获取锁的过程中不允许被打断,不立即响应打断,继续尝试获取锁。
// AbstractQueuedSynchronizer
final int acquire(...) {
for (;;) {
...
{
...
// 被打断且可被打断
if ((interrupted |= Thread.interrupted()) && interruptible)
break;
}
}
// (等待超时)或者(被打断且可被打断)则取消获取锁
return cancelAcquire(node, interrupted, interruptible);
}
公平锁的实现原理
通过 ReentrantLock 的有参构造可创建公平锁。
// ReentrantLock
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
FairSync 和 NonfairSync 的区别即为公平锁和非公平锁的区别,主要关注 initialTryLock 方法。
公平锁在初次尝试获取锁时,仅当锁未被占有且等待队列无等待线程时,当前线程才会立即尝试获取锁,否则将加入等待队列队尾。
// ReentrantLock
static final class FairSync extends Sync {
private static final long serialVersionUID = -3000897897090466540L;
// 初次尝试获取锁
final boolean initialTryLock() {
Thread current = Thread.currentThread();
int c = getState();
// 锁未被占有
if (c == 0) {
// 等待队列无未取消的等待线程 且 获取锁成功
if (!hasQueuedThreads() && compareAndSetState(0, 1)) {
// 将锁的持有者设为当前线程
setExclusiveOwnerThread(current);
return true;
}
} else if (getExclusiveOwnerThread() == current) {
// 重入
if (++c < 0)
throw new Error("Maximum lock count exceeded");
setState(c);
return true;
}
return false;
}
// 非初次尝试获取锁
protected final boolean tryAcquire(int acquires) {
if (
// 锁未被占有
getState() == 0 &&
// 等待队列无未取消的等待线程
!hasQueuedPredecessors() &&
// 获取锁成功
compareAndSetState(0, acquires)
) {
// 将锁的持有者设为当前线程
setExclusiveOwnerThread(Thread.currentThread());
return true;
}
return false;
}
}
hasQueuedThread() 用于判断等待队列中是否未取消的等待线程。
// AbstractQueuedSynchronizer
public final boolean hasQueuedThreads() {
for (Node p = tail, h = head; p != h && p != null; p = p.prev)
// 存在未取消的线程
if (p.status >= 0)
return true;
return false;
}
条件变量的实现原理
ReentrantLock 通过 newCondition() 方法创建条件变量,而 ReentrantLock 的 newCondition() 方法基于同步器的 newCondition() 方法。
// ReentrantLock
public Condition newCondition() {
return sync.newCondition();
}
同步器的 newCondition() 方法会创建一个 ConditionObject 对象,即条件变量对象。
// Sync extends AbstractQueuedSynchronizer
final ConditionObject newCondition() {
return new ConditionObject();
}
每个条件变量维护一个条件变量队列。
// ReentrantLock
public class ConditionObject implements Condition{
// 头节点
private transient ConditionNode firstWaiter;
// 尾节点
private transient ConditionNode lastWaiter;
}
线程的等待和唤醒可粗略理解为
- 线程等待:先将线程从等待队列中移除,再将线程加入条件变量队列
- 线程唤醒:先将线程从条件变量队列中移除,再将线程加入等待队列
- 条件变量队列中的线程不能参与锁的竞争,而等待队列中的线程可以参与锁的竞争
加入条件变量队列的流程
// ReentrantLock
public class ConditionObject implements Condition{
// 将线程加入条件变量队列
public final void await() throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
// 创建节点,创建失败则自旋尝试获取锁
ConditionNode node = newConditionNode();
// 创建节点失败
if (node == null)
return;
// 将当前线程加入条件变量队列
// 当前线程释放持有的锁(会将当前线程从等待队列溢出)并唤醒等待队列下一个线程
// 返回重入次数
int savedState = enableWait(node);
// 当前线程等待原因置为this,常用于调试
LockSupport.setCurrentBlocker(this); // for back-compatibility
boolean interrupted = false, cancelled = false, rejected = false;
// !(可以尝试获取锁)
while (!canReacquire(node)) {
if (interrupted |= Thread.interrupted()) {
if (cancelled = (node.getAndUnsetStatus(COND) & COND) != 0)
break; // else interrupted after signal
} else if ((node.status & COND) != 0) {
// 陷入等待
try {
if (rejected)
node.block();
else
ForkJoinPool.managedBlock(node);
} catch (RejectedExecutionException ex) {
// ForkJoinPool线程池无法接收任务
rejected = true;
} catch (InterruptedException ie) {
interrupted = true;
}
} else
Thread.onSpinWait();
}
// 当前线程等待原因置为null
LockSupport.setCurrentBlocker(null);
// 重新参与竞争
node.clearStatus();
acquire(node, savedState, false, false, false, 0L);
if (interrupted) {
if (cancelled) {
unlinkCancelledWaiters(node);
throw new InterruptedException();
}
Thread.currentThread().interrupt();
}
}
}
// ConditionObject implements Condition
private ConditionNode newConditionNode() {
int savedState;
// 初始化等待队列头节点
if (tryInitializeHead() != null) {
try {
return new ConditionNode();
} catch (OutOfMemoryError oome) {
}
}
// 发生OutOfMemoryError时才会往下执行
// 当前线程未持有锁或者释放锁失败
if (!isHeldExclusively() || !release(savedState = getState()))
throw new IllegalMonitorStateException();
// 当前线程暂停一段时间
U.park(false, OOME_COND_WAIT_DELAY);
// 自旋尝试获取锁
acquireOnOOME(false, savedState);
return null;
}
// ConditionObject implements Condition
private int enableWait(ConditionNode node) {
// 当前线程持有锁才可以加入条件变量队列
if (isHeldExclusively()) {
// 设置节点信息
node.waiter = Thread.currentThread();
node.setStatusRelaxed(COND | WAITING);
// 将节点加入条件变量队列
ConditionNode last = lastWaiter;
if (last == null)
firstWaiter = node;
else
last.nextWaiter = node;
lastWaiter = node;
// 当前线程的重入次数
int savedState = getState();
// 释放锁返回重入次数
if (release(savedState))
return savedState;
}
// 未持有锁或者释放锁失败则抛出异常
node.status = CANCELLED;
throw new IllegalMonitorStateException();
}
// ConditionObject implements Condition
private boolean canReacquire(ConditionNode node) {
Node p;
// node和p的链接关系没有被破坏或者node在等待队列中
return node != null &&
(p = node.prev) != null &&
(p.next == node || isEnqueued(node));
}
移出条件变量队列的流程
// ConditionObject implements Condition
public final void signal() {
ConditionNode first = firstWaiter;
// 持有锁的线程才能唤醒条件变量队列中的线程
if (!isHeldExclusively())
throw new IllegalMonitorStateException();
else if (first != null)
doSignal(first, false);
}
// ConditionObject implements Condition
private void doSignal(ConditionNode first, boolean all) {
while (first != null) {
ConditionNode next = first.nextWaiter;
// 将条件变量队列中的第一个等待线程移除
if ((firstWaiter = next) == null)
lastWaiter = null;
// 将刚从条件变量队列中移除的等待线程加入等待队列
if ((first.getAndUnsetStatus(COND) & COND) != 0) {
// 加入等待队列
enqueue(first);
// 不是唤醒所有线程
if (!all)
break;
}
// 由于线程被取消等原因可能导致线程无法加入等待队列
// 此时尝试等待队列的下一个线程
first = next;
}
}
// ConditionObject implements Condition
final void enqueue(ConditionNode node) {
if (node != null) {
// 是否立即唤醒线程node
boolean unpark = false;
for (Node t;;) {
if ((t = tail) == null && (t = tryInitializeHead()) == null) {
// 等待队列为null且初始化头节点失败时,应立即唤醒线程node
unpark = true;
break;
}
// 设置前驱
node.setPrevRelaxed(t);
// 通过CAS操作将等待队列队尾置为node
if (casTail(t, node)) {
t.next = node;
// 等待队列队尾被取消,则唤醒线程node,以清理队列
if (t.status < 0)
unpark = true;
break;
}
}
// 立即唤醒线程node
if (unpark)
LockSupport.unpark(node.waiter);
}
}
END
如果觉得本文对您有一点点帮助,欢迎点赞、转发加关注,这会对我有非常大的帮助,如果有任何问题,欢迎在评论区留言或者后台私信,咱们下期见!
文章文档:公众号 字节幺零二四
回复关键字可获取本文文档。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。