之前总结过AQS相关的源码,但是格式比较乱,没法看,有些问题也不是很清楚,这段沉淀时间再瞻仰一次
大家推荐个靠谱的公众号程序员探索之路,大家一起加油
目录
从ReentranLock看AQS
ReentramLock构造函数
从构造函数可以看出,默认为非公平锁,传true为公平锁
public ReentrantLock() {
sync = new NonfairSync();
}
/**
* Creates an instance of {@code ReentrantLock} with the
* given fairness policy.
*
* @param fair {@code true} if this lock should use a fair ordering policy
*/
public ReentrantLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
}
非平锁
类关系图:
实例方式:
ReentrantLock reentrantLock = new ReentrantLock(false);
或者
ReentrantLock reentrantLock = new ReentrantLock();
抢锁(没有设置超时时间):
rentrantLock.lock();
位置:ReentrantLock 205行
方法流程:
直接cas设置锁状态如果成功 设置当前持有锁的线程
如果失败acquire(1) 也就是抢锁
final void lock() {
if (compareAndSetState(0, 1))
setExclusiveOwnerThread(Thread.currentThread());
else
acquire(1);
}
compareAndSetState(0, 1) setExclusiveOwnerThread(Thread.currentThread() 方法不再分析
acruire(1)
位置:AbstractQueuedSynchronizer 1197行
方法流程:
- 竞争锁 上面不是竞争失败了吗?怎么还竞争,万一此时释放了呢
- 如果竞争锁失败 添加在阻塞队列中
- 如果竞争锁和添加在阻塞队列中都失败 中断该线程就是设置中断标志位
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
tryAcquire(arg)
位置:ReentrantLock 212行
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
nonfairTryAcquire(acquires)
位置:ReentrantLock 129行
方法流程:
- 如果当前锁状态为0 表示没有线程占用该锁 那么就cas抢占 设置当前持有锁的线程 返回true
- 如果不是0,但是占用锁的线程是当前线程,那就是重入 把锁状态 +1不需要cas 返回true
- 如果上面两个都不成立 返回false
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
//当前锁状态为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;
}
//上面两个都不成立
return false;
}
acquireQueued(addWaiter(Node.EXCLUSIVE), arg)
addWaiter(Node.EXCLUSIVE)
位置:AbstractQueuedSynchronizer 605
方法目的:阻塞队列初始化(如果没有的话),将当前线程加入到阻塞队列中 返回添加到队尾的node
方法流程:
- 如果队尾不为null,说明已经初始化过,将node加入到队尾即可,注意这里细节,node的前驱为队尾,然后cas设置node为队尾 如果成功设置原队尾的next为node(现在的队尾) 为什么cas设置 因为有并发的可能
- 如果队尾为null 说明没有初始化阻塞队列,进行初始化,把node加入到队尾
private Node addWaiter(Node mode) {
Node node = new Node(Thread.currentThread(), mode);
// Try the fast path of enq; backup to full enq on failure
Node pred = tail;
if (pred != null) {
node.prev = pred;
if (compareAndSetTail(pred, node)) {
pred.next = node;
return node;
}
}
enq(node);
return node;
}
enq(node)
位置:AbstractQueuedSynchronizer 583
方法目的:阻塞队列初始化(如果没有的话),将当前线程加入到阻塞队列中
方法流程:
- 如果队尾为null 设置队头为空node 队尾 = 队头
- 自旋设置node为队尾节点
private Node enq(final Node node) {
for (;;) {
Node t = tail;
//如果队尾为null
if (t == null) { // Must initialize
if (compareAndSetHead(new Node()))
tail = head;
} else {
//设置node为队尾节点
node.prev = t;
if (compareAndSetTail(t, node)) {
t.next = node;
return t;
}
}
}
}
acquireQueued
位置:AbstractQueuedSynchronizer 857
方法目的:
方法流程:
- 如果node的前驱是head 而且抢到锁 那么 node设置为head
- 如果上面条件不符合 把node前驱的waitStatus设置SIGNAL 挂起node所在的线程
- 如果上面出现任何异常 取消节点
final boolean acquireQueued(final Node node, int arg) {
boolean failed = true;
try {
boolean interrupted = false;
for (;;) {
final Node p = node.predecessor();
//如果node的前驱是head 而且抢到锁
if (p == head && tryAcquire(arg)) {
setHead(node);
p.next = null; // help GC
failed = false;
return interrupted;
}
//一般判断这个节点需不需要挂起 第一次都是返回false 因为只有
添加节点了 才会把前驱节点的等待状态设置为
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
interrupted = true;
}
} finally {
//取消操作后面分析
if (failed)
cancelAcquire(node);
}
}
shouldParkAfterFailedAcquire(p, node)
位置:AbstractQueuedSynchronizer 795
方法目的:判断当前线程是否需要挂起
方法流程:
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
int ws = pred.waitStatus;
//正常情况
if (ws == Node.SIGNAL)
/*
* This node has already set status asking a release
* to signal it, so it can safely park.
*/
return true;
/**
大于0表示 前驱节点已经取消了(可以看看前面node状态的取值)
那就往前找前驱 直到 不是大于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 {
/**这种情况就是把 前驱的waitStatuscas为SIGNAL就行了
/*
* waitStatus must be 0 or PROPAGATE. Indicate that we
* need a signal, but don't park yet. Caller will need to
* retry to make sure it cannot acquire before parking.
*/
compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
}
return false;
}
parkAndCheckInterrupt()
位置:AbstractQueuedSynchronizer 795
方法目的:将当前线程挂起,返回当前线程中断状态
方法流程:
private final boolean parkAndCheckInterrupt() {
LockSupport.park(this);
return Thread.interrupted();
}
大致流程:设置锁状态 成功 就已经抢到锁了;失败,进入阻塞队列
取消节点
需要干什么事,假设需要取消的节点为node,如果node的前驱不是取消,那么只需要修改指针略过node即可,如果不是需要处理
位置:AbstractQueuedSynchronizer 742
方法目的:取消节点
方法流程:
private void cancelAcquire(Node node) {
// 忽略不存在的node
if (node == null)
return;
node.thread = null;
// Skip cancelled predecessors
Node pred = node.prev;
//如果node的前驱 是取消的节点 那么一直往前找 直到找到没有取消的节点
while (pred.waitStatus > 0)
node.prev = pred = pred.prev;
// predNext is the apparent node to unsplice. CASes below will
// fail if not, in which case, we lost race vs another cancel
// or signal, so no further action is necessary.
Node predNext = pred.next;
// Can use unconditional write instead of CAS here.
// After this atomic step, other Nodes can skip past us.
// Before, we are free of interference from other threads.
node.waitStatus = Node.CANCELLED;
// 如果node是队尾 那么直接把 前驱的后继设置为null即可.
if (node == tail && compareAndSetTail(node, pred)) {
compareAndSetNext(pred, predNext, null);
} else {
// If successor needs signal, try to set pred's next-link
// so it will get one. Otherwise wake it up to propagate.
int ws;
//如果 pred不是头结点 而且 pred的waitStatus是允许唤醒后继的那么就将node略过
if (pred != head &&
((ws = pred.waitStatus) == Node.SIGNAL ||
(ws <= 0 && compareAndSetWaitStatus(pred, ws, Node.SIGNAL))) &&
pred.thread != null) {
Node next = node.next;
if (next != null && next.waitStatus <= 0)
compareAndSetNext(pred, predNext, next);
} else {
//如果pred是头结点 或者 pred的waitStatus是不允许唤醒后继
pred的next是node node还取消
所以直接唤醒 node的next就ok了
unparkSuccessor(node);
}
node.next = node; // help GC
}
}
释放锁:
rentrantLock.unlock();
public void unlock() {
sync.release(1);
}
release(1)
位置:AbstractQueuedSynchronizer 1260
方法目的:释放锁 如果阻塞队列已经初始化 而且头结点的waitStatus不为0
唤醒线程
public final boolean release(int arg) {
if (tryRelease(arg)) {
Node h = head;
if (h != null && h.waitStatus != 0)
unparkSuccessor(h);
return true;
}
return false;
}
tryRelease(arg)
位置:ReentrantLock 148
方法目的:释放锁
方法流程:
- C = 当前锁状态 – 1
- 如果c == 0锁无线程使用 fanhuitrue
- 如果 不是 说明锁有重入情况 特殊处理
protected final boolean tryRelease(int releases) {
//计算释放锁后的锁状态
int c = getState() - releases;
if (Thread.currentThread() != getExclusiveOwnerThread())
throw new IllegalMonitorStateException();
boolean free = false;
//如果c == 0
if (c == 0) {
free = true;
setExclusiveOwnerThread(null);
}
setState(c);
return free;
}
unparkSuccessor(h)
位置:AbstractQueuedSynchronizer 148
方法目的:唤醒 head的后继节点
方法流程:
private void unparkSuccessor(Node node) {
/*
* If status is negative (i.e., possibly needing signal) try
* to clear in anticipation of signalling. It is OK if this
* fails or if status is changed by waiting thread.
*/
int ws = node.waitStatus;
//这里为什么要用cas呢? 因为tryRelease已经把锁状态改变了呀
if (ws < 0)
compareAndSetWaitStatus(node, ws, 0);
//这里为什么循环呢 因为后继节点有可能取消了 那就从后往前找找到第一个 没有取消的节点
Node s = node.next;
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;
}
//唤醒 s节点的线程 然后接着上面的挂起地方继续执行 抢锁。。。。
if (s != null)
LockSupport.unpark(s.thread);
}
大致流程:释放锁,唤醒后继节点
总结:
主要通过四个部件协调并发
- 锁状态 private volatile int state 来控制是否抢到锁,释放锁
- 节点等待状态 waitStatus
- 挂起,唤醒线程方法
LockSupport.park(this);
LockSupport.unpark(s.thread);
- 阻塞队列,将挂起的线程排队
抢锁(设置超时时间)
除了加了一个判断超时间的逻辑其他地方都一样
使用示例:
reentrantLock.tryLock(1000, TimeUnit.SECONDS)
tryLock(1000, TimeUnit.SECONDS)
位置:ReentrantLock 440
public boolean tryLock(long timeout, TimeUnit unit)
throws InterruptedException {
return sync.tryAcquireNanos(1, unit.toNanos(timeout));
}
位置:AbstractQueuedSynchronizer 1242
方法流程:tryAcquire(arg)和上面分析的一样就不分析了
public final boolean tryAcquireNanos(int arg, long nanosTimeout)
throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
return tryAcquire(arg) ||
doAcquireNanos(arg, nanosTimeout);
}
doAcquireNanos(arg, nanosTimeout)
位置:AbstractQueuedSynchronizer 913
方法目的:在限定的时间内获取锁
方法流程:其实除了增加一个是否超时
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();
//如果 超时了 直接返回false 会走到下面的 finally块中 此时 failed = true 所以 会取消节点
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);
}
}
公平锁
类关系图:
实例方式:
ReentrantLock reentrantLock = new ReentrantLock(true);
抢锁(没有设置超时时间)
其实就是获取锁的时候和 非公平锁有区别 其他的没有
位置:ReentrantLock 223
方法目的:
方法流程:
final void lock() {
acquire(1);
}
位置:ReentrantLock 231
方法目的:
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;
}