ReentrantLock继承体系
Lock接口中主要定义了 获取锁、尝试获取锁、释放锁、条件锁等几个方法。
构造方法
//非公平锁
public ReentrantLock() {
sync = new NonfairSync();
}
//true公平锁,false非公平锁
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
主要内部类
abstract static class Sync extends AbstractQueuedSynchronizer{}
static final class FairSync extends Sync {}
static final class NonfairSync extends Sync {}
抽象类Sync实现了AQS的部分方法;
NonfairSync实现了Sync,主要用于非公平锁的获取;
FairSync实现了Sync,主要用于公平锁的获取
lock方法分析
public void lock() {
sync.lock();
}
调用的同步器的lock方法。
FairSync的lock()
final void lock() {
acquire(1);
}
//AbstractQueuedSynchronizer 的acquire
public final void acquire(int arg) {
//尝试获取锁,如果失败了就加入队列排队。
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
// ReentrantLock.FairSync.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;
}
hasQueuedPredecessors方法
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());
}
获取锁失败加入队列
private Node addWaiter(Node mode) {
//构建节点
Node node = new Node(Thread.currentThread(), mode);
Node pred = tail;
//尾节点不为空,尝试把更新尾结点
if (pred != null) {
//新的尾结点的前一个节点设置为旧的尾结点
node.prev = pred;
//更新尾结点
if (compareAndSetTail(pred, node)) {
//更新成功设置旧尾结点的下一个结点为新的尾结点
pred.next = node;
//返回新节点
return node;
}
}
//尾结点为空,或者尝试加入新节点失败,就CAS自旋不断尝试直到成功。
enq(node);
return node;
}
private Node enq(final Node node) {
for (;;) {
Node t = tail;
//尾结点为空初始化
if (t == null) { // Must initialize
if (compareAndSetHead(new Node()))
tail = head;
} else {
//CAS更新尾节点为新节点。
node.prev = t;
if (compareAndSetTail(t, node)) {
// 如果成功了,把旧尾节点的下一个节点指向新节点
t.next = node;
//返回新节点
return t;
}
}
}
}
//这个方法是尝试让对列中的节点依次来获取锁
final boolean acquireQueued(final Node node, int arg) {
boolean failed = true;
try {
boolean interrupted = false;
for (;;) {
//前一个节点
final Node p = node.predecessor();
//前一个节点是头结点尝试获取锁
if (p == head && tryAcquire(arg)) {
// 尝试获取锁成功
// 这里同时只会有一个线程在执行,所以不需要用CAS更新
// 把当前节点设置为新的头节点
setHead(node);
// 并把上一个节点从链表中删除
p.next = null; // help GC
failed = false;
return interrupted;
}
//前一个节点不是头结点,或者获取锁失败
// // 是否需要阻塞
if (shouldParkAfterFailedAcquire(p, node) &&
// 真正阻塞的方法
parkAndCheckInterrupt())
interrupted = true;
}
} finally {
if (failed)
cancelAcquire(node);
}
}
// 第一次调用会把前一个节点的等待状态设置为SIGNAL,并返回false
// 第二次调用才会返回true
//static final int CANCELLED = 1;
//static final int SIGNAL = -1;
//static final int CONDITION = -2;
//static final int PROPAGATE = -3;
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
int ws = pred.waitStatus;
// 如果前一个节点的状态为SIGNAL(等待唤醒),直接返回true
if (ws == Node.SIGNAL)
return true;
// 如果前一个节点的状态大于0,也就是已取消状态
if (ws > 0) {
// 把前面所有取消状态的节点都从链表中删除
/*
* Predecessor was cancelled. Skip over predecessors and
* indicate retry.
*/
do {
node.prev = pred = pred.prev;
} while (pred.waitStatus > 0);
pred.next = node;
} else {
// 如果前一个节点的状态小于等于0,则把其状态设置为等待唤醒
// 这里可以简单地理解为把初始状态0设置为SIGNAL
// CONDITION是条件锁的时候使用的
// PROPAGATE是共享锁使用的
compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
}
return false;
}
获取锁的主要过程大致如下:
(1)没有排队的线程,就尝试获取锁尝试获取锁,如果获取到了就直接返回了;
(2)尝试获取锁失败,再调用addWaiter()构建新节点并尝试把新节点入队;
(3)入队失败则CAS循化更新尾结点直到入队成功。
(4)然后调用acquireQueued()再次尝试获取锁,如果成功了,直接返回;
(5)如果再次失败,再调用shouldParkAfterFailedAcquire()将节点的等待状态置为等待唤醒(SIGNAL);
(6)调用parkAndCheckInterrupt()阻塞当前线程;
(7)如果被唤醒了,会继续在acquireQueued()的for()循环再次尝试获取锁,如果成功了就返回;
(8)如果不成功,再次阻塞,重复(4)(5)(6)直到成功获取到锁。
以上就是整个公平锁获取锁的过程。
独占式同步状态的获取流程
NonfairSync的lock()
// ReentrantLock.lock()
public void lock() {
sync.lock();
}
// ReentrantLock.NonfairSync.lock()
// 这个方法在公平锁模式下是直接调用的acquire(1);
final void lock() {
// 直接尝试CAS更新状态变量
if (compareAndSetState(0, 1))
// 如果更新成功,说明获取到锁,把当前线程设为独占线程
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
}
//AbstractQueuedSynchronizer 的acquire
public final void acquire(int arg) {
//尝试获取锁,如果失败了就加入队列排队。
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
// ReentrantLock.NonfairSync.tryAcquire()
protected final boolean tryAcquire(int acquires) {
// 调用父类的方法
return nonfairTryAcquire(acquires);
}
// ReentrantLock.Sync.nonfairTryAcquire()
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
// 如果状态变量的值为0,再次尝试CAS更新状态变量的值
// 相对于公平锁模式少了!hasQueuedPredecessors()条件
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;
}
相对于公平锁,非公平锁加锁的过程主要有两点不同:
(1)一开始就尝试CAS更新状态变量state的值,如果成功了就获取到锁了;
(2)在tryAcquire()的时候没有检查是否前面有排队的线程,直接上去获取锁才不管别人有没有排队呢;
总的来说,相对于公平锁,非公平锁在一开始就多了两次直接尝试获取锁的过程。
tryLock()方法
尝试获取一次锁,成功了就返回true,没成功就返回false,不会继续尝试。
// ReentrantLock.tryLock()
public boolean tryLock() {
return sync.nonfairTryAcquire(1);
}
// ReentrantLock.Sync.nonfairTryAcquire()
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;
}
tryLock()方法比较简单,直接以非公平的模式去尝试获取一次锁,获取到了或者锁本来就是当前线程占有着就返回true,否则返回false。
tryLock(long time, TimeUnit unit)方法
尝试获取锁,并等待一段时间,如果在这段时间内都没有获取到锁,就返回false。
// ReentrantLock.tryLock()
public boolean tryLock(long timeout, TimeUnit unit)
throws InterruptedException {
return sync.tryAcquireNanos(1, unit.toNanos(timeout));
}
// AbstractQueuedSynchronizer.tryAcquireNanos()
public final boolean tryAcquireNanos(int arg, long nanosTimeout)
throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
// 先尝试获取一次锁
return tryAcquire(arg) ||
doAcquireNanos(arg, nanosTimeout);
}
// AbstractQueuedSynchronizer.doAcquireNanos()
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;
// spinForTimeoutThreshold = 1000L;
// 只有到期时间大于1000纳秒,才阻塞
// 小于等于1000纳秒,直接自旋解决就得了
if (shouldParkAfterFailedAcquire(p, node) &&
nanosTimeout > spinForTimeoutThreshold)
LockSupport.parkNanos(this, nanosTimeout);
if (Thread.interrupted())
throw new InterruptedException();
}
} finally {
if (failed)
cancelAcquire(node);
}
}
unlock()方法
// java.util.concurrent.locks.ReentrantLock.unlock()
public void unlock() {
sync.release(1);
}
// java.util.concurrent.locks.AbstractQueuedSynchronizer.release
public final boolean release(int arg) {
if (tryRelease(arg)) {
Node h = head;
// 如果头节点不为空,且等待状态不是0,就唤醒下一个节点
// 在每个节点阻塞之前会把其上一个节点的等待状态设为SIGNAL(-1)
// 所以,SIGNAL的准确理解应该是唤醒下一个等待的线程
if (h != null && h.waitStatus != 0)
unparkSuccessor(h);
return true;
}
return false;
}
// java.util.concurrent.locks.ReentrantLock.Sync.tryRelease
protected final boolean tryRelease(int releases) {
int c = getState() - releases;
// 如果当前线程不是占有着锁的线程,抛出非法监视器异常异常
if (Thread.currentThread() != getExclusiveOwnerThread())
throw new IllegalMonitorStateException();
boolean free = false;
// 如果状态变量的值为0了,说明完全释放了锁
// 这也就是为什么重入锁调用了多少次lock()就要调用多少次unlock()的原因
// 如果不这样做,会导致锁不会完全释放,别的线程永远无法获取到锁
if (c == 0) {
free = true;
setExclusiveOwnerThread(null);
}
setState(c);
return free;
}
// java.util.concurrent.locks.AbstractQueuedSynchronizer.unparkSuccessor
private void unparkSuccessor(Node node) {
//node是头节点
int ws = node.waitStatus;
// 如果头节点的等待状态小于0,就把它设置为0
//static final int CANCELLED = 1;
//static final int SIGNAL = -1;
//static final int CONDITION = -2;
//static final int PROPAGATE = -3;
if (ws < 0)
compareAndSetWaitStatus(node, ws, 0);
Node s = node.next;
// 如果下一个节点为空,或者其等待状态大于0(实际为已取消)
if (s == null || s.waitStatus > 0) {
s = null;
// 从尾节点向前遍历取到队列最前面的那个状态不是已取消状态的节点
for (Node t = tail; t != null && t != node; t = t.prev)
if (t.waitStatus <= 0)
s = t;
}
// 如果下一个节点不为空,则唤醒它
if (s != null)
LockSupport.unpark(s.thread);
}
释放锁的过程大致为:
(1)将state的值减1;
(2)如果state减到了0,说明已经完全释放锁了,唤醒下一个等待着的节点;
条件锁
一般这么用
public static void main(String[] args) {
ReentrantLock lock = new ReentrantLock();
Condition condition = lock.newCondition();
new Thread(() -> {
try {
lock.lock();
condition.await();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}).start();
try {
Thread.sleep(1000);
lock.lock();
condition.signal();
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
lock.unlock();
}
}
lock.newCondition()方法
新建一个条件锁。
// ReentrantLock.newCondition()
public Condition newCondition() {
return sync.newCondition();
}
// ReentrantLock.Sync.newCondition()
final ConditionObject newCondition() {
return new ConditionObject();
}
// AbstractQueuedSynchronizer.ConditionObject.ConditionObject()
public ConditionObject() { }
ConditionObject的主要属性
private static final long serialVersionUID = 1173984872572414699L;
/** First node of condition queue. */
private transient Node firstWaiter;
/** Last node of condition queue. */
private transient Node lastWaiter;
// AbstractQueuedSynchronizer.ConditionObject.await()
public final void await() throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
//添加节点到条件队列(和AQS队列不同)中,
Node node = addConditionWaiter();
//完全释放当前线程所占的锁
int savedState = fullyRelease(node);
int interruptMode = 0;
//是否在同步队列中
while (!isOnSyncQueue(node)) {
//阻塞当前线程
LockSupport.park(this);
// 上面部分是调用await()时释放自己占有的锁,并阻塞自己等待条件的出现
// *************************分界线************************* //
// 下面部分是条件已经出现,尝试去获取锁
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);
}
// AbstractQueuedSynchronizer.ConditionObject.addConditionWaiter
private Node addConditionWaiter() {
Node t = lastWaiter;
// If lastWaiter is cancelled, clean out.
//如果队列的尾结点已取消,从头节点开始清除取消的结点。
if (t != null && t.waitStatus != Node.CONDITION) {
unlinkCancelledWaiters();
//重新获取尾结点
t = lastWaiter;
}
//构建尾结点
Node node = new Node(Thread.currentThread(), Node.CONDITION);
//条件队列为空,首节点就是node
if (t == null)
firstWaiter = node;
//否则旧的尾结点的下个结点是node
else
t.nextWaiter = node;
//返回新的尾结点
lastWaiter = node;
return node;
}
// AbstractQueuedSynchronizer.ConditionObject.unlinkCancelledWaiters
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;
}
}
unlinkCancelledWaiters 作用断开所有是cancelled的结点。
//完全释放锁
final int fullyRelease(Node node) {
boolean failed = true;
try {
// 获取状态变量的值,重复获取锁,这个值会一直累加
// 所以这个值也代表着获取锁的次数
int savedState = getState();
// 一次性释放所有获得的锁
if (release(savedState)) {
failed = false;
// 返回获取锁的次数
return savedState;
//释放失败!上锁且释放失败,必是异常的发生
} else {
throw new IllegalMonitorStateException();
}
} finally {
//完全释放失败则标记尾结点为CANCELLED
if (failed)
node.waitStatus = Node.CANCELLED;
}
}
// AbstractQueuedSynchronizer.isOnSyncQueue
final boolean isOnSyncQueue(Node node) {
// 如果等待状态是CONDITION,或者前一个指针为空,返回false
// 说明还没有移到AQS的队列中
if (node.waitStatus == Node.CONDITION || node.prev == null)
return false;
// 如果next指针有值,说明已经移到AQS的队列中了
if (node.next != null) // If has successor, it must be on queue
return true;
// 从AQS的尾节点开始往前寻找看是否可以找到当前节点,找到了也说明已经在AQS的队列中了
return findNodeFromTail(node);
}
//从AQS的尾节点开始往前寻找看是否可以找到当前节点
private boolean findNodeFromTail(Node node) {
Node t = tail;
for (;;) {
if (t == node)
return true;
if (t == null)
return false;
t = t.prev;
}
}
await()方法的大致流程:
(1)新建一个节点加入到条件队列中去;
(2)完全释放当前线程占有的锁;
(3)阻塞当前线程,并等待条件的出现;
(4)条件已出现(此时节点已经移到AQS的队列中),尝试获取锁;
condition.signal()方法
// AbstractQueuedSynchronizer.ConditionObject.signal
public final void signal() {
// 如果不是当前线程占有着锁,调用这个方法抛出异常
// 说明signal()也要在获取锁之后执行
if (!isHeldExclusively())
throw new IllegalMonitorStateException();
// 条件队列的头节点
Node first = firstWaiter;
// 如果有等待条件的节点,则通知它条件已成立
if (first != null)
doSignal(first);
}
// AbstractQueuedSynchronizer.ConditionObject.doSignal
private void doSignal(Node first) {
do {
// 移到条件队列的头节点往后一位
if ( (firstWaiter = first.nextWaiter) == null)
lastWaiter = null;
// 相当于把头节点从队列中出队
first.nextWaiter = null;
// 转移节点到AQS队列中
} while (!transferForSignal(first) &&
(first = firstWaiter) != null);
}
// AbstractQueuedSynchronizer.transferForSignal
final boolean transferForSignal(Node node) {
// 把节点的状态更改为0,也就是说即将移到AQS队列中
// 如果失败了,说明节点已经被改成取消状态了
// 返回false,通过上面的循环可知会寻找下一个可用节点
if (!compareAndSetWaitStatus(node, Node.CONDITION, 0))
return false;
// 调用AQS的入队方法把节点移到AQS的队列中
// 注意,这里enq()的返回值是node的上一个节点,也就是旧尾节点
Node p = enq(node);
// 上一个节点的等待状态
int ws = p.waitStatus;
// 如果上一个节点已取消了,或者更新状态为SIGNAL失败(也是说明上一个节点已经取消了)
// 则直接唤醒当前节点对应的线程
if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL))
LockSupport.unpark(node.thread);
// 如果更新上一个节点的等待状态为SIGNAL成功了
// 则返回true,这时上面的循环不成立了,退出循环,也就是只通知了一个节点
// 此时当前节点还是阻塞状态
// 也就是说调用signal()的时候并不会真正唤醒一个节点
// 只是把节点从条件队列移到AQS队列中
return true;
}
signal()方法的大致流程为:
(1)从条件队列的头节点开始寻找一个非取消状态的节点;
(2)把它从条件队列移到AQS队列;
(3)且只移动一个节点;