上节我们讲了锁,可以基于volatile + CAS 实现同步锁,这一节我们就来看看java中的锁是怎么利用这一点实现的。
AbstractQueuedSynchronizer
说到锁,我们不得不提到AbstractQueuedSynchronizer(AQS)。AQS其实就是基于volatile+cas实现的锁模板。
public class AbstractQueuedSynchronizer{
//线程节点
static final class Node {
...
volatile Node prev;
volatile Node next;
volatile Thread thread;
...
}
....
//head 等待队列头尾节点
private transient volatile Node head;
private transient volatile Node tail;
// The synchronization state. 同步状态
private volatile int state;
...
//提供CAS操作,状态具体的修改由子类实现
protected final boolean compareAndSetState(int expect, int update) {
return unsafe.compareAndSet(this, expect, update);
}
...
//线程会先尝试获取锁,失败则封装成Node
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
...
//CAS加入同步队列的尾部,尝试加锁(可能前驱节点刚好释放锁),否则线程进入阻塞等待
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;
}
...
private Node enq(final Node node) {
//通过for循环来将node节点置为tail节点
for (;;) {
Node t = tail;
if (t == null) { // Must initialize
//初始化头结点
if (compareAndSetHead(new Node()))
tail = head;
} else {
node.prev = t;
//执行成功表明node节点成功置为tail节点,若失败,可能是由其他的线程也在进行此操作
if (compareAndSetTail(t, node)) {
t.next = node;
return t;
}
}
}
}
}
AQS内部维护一个同步队列,元素就是包装了线程的Node
同步队列中首节点是获取到锁的节点,它在释放锁的时会唤醒后继节点,后继节点获取到锁的时候,会把自己设为首节点。
线程会先尝试获取锁,失败则封装成Node,CAS加入同步队列的尾部。在加入同步队列的尾部时,会判断前驱节点是否是head结点,并尝试加锁(可能前驱节点刚好释放锁),否则线程进入阻塞等待。
这里注意,tryAcquire(arg)尝试获取锁里面没有东西,直接抛异常,why?这个就和抽象方法一样,需要你重写,所以AQS的子类都会重写这个方法。
ConditionObject
//AbstractQueuedSynchronizer.java
public class ConditionObject implements Condition, java.io.Serializable {
//条件队列;Node 复用了AQS中定义的Node
private transient Node firstWaiter;
private transient Node lastWaiter;
...
public final void await() throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
Node node = addConditionWaiter();//构造Node,加入条件队列
int savedState = fullyRelease(node);
int interruptMode = 0;
while (!isOnSyncQueue(node)) {
LockSupport.park(this);//挂起线程
if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)
break;
}
//notify唤醒线程后,加入同步队列继续竞争锁
if (acquireQueued(node, savedState) && interruptMode != THROW_IE)
interruptMode = REINTERRUPT;
if (node.nextWaiter != null) // clean up if cancelled
unlinkCancelledWaiters();
if (interruptMode != 0)
reportInterruptAfterWait(interruptMode);
}
...
//类似Object.notify
private void doSignal(Node first) {
do {
if ( (firstWaiter = first.nextWaiter) == null)
lastWaiter = null;
first.nextWaiter = null;
} while (!transferForSignal(first) &&
(first = firstWaiter) != null);
}
每个Condition对象内部包含一个Node元素的FIFO条件队列
当一个线程调用Condition.await()方法,那么该线程将会释放锁、构造Node加入条件队列并进入等待状态
调用Condition.signal时,获取条件队列的首节点,将其移动到同步队列并且利用LockSupport唤醒节点中的线程。随后继续执行wait挂起前的状态,调用acquireQueued(node, savedState)竞争同步状态。
最后来个完整的图解:
ReentrantLock
ReentrantLock实现了Lock接口,并使用内部类Sync(Sync继承AbstractQueuedSynchronizer)来实现同步操作
public class ReentrantLock implements Lock, java.io.Serializable {
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() ;另一个含有布尔参数public ReentrantLock(boolean fair)。后面一个构造函数说明ReentrantLock可以新建公平锁;而Synchronized只能建立非公平锁。
ReentrantLock内部类:
abstract static class Sync extends AbstractQueuedSynchronizer{
....
final boolean nonfairTryAcquire(int acquires) {
final Thread current = Thread.currentThread();
int c = getState();
if (c == 0) {
//直接CAS状态加锁,非公平操作
if (compareAndSetState(0, acquires)) {
setExclusiveOwnerThread(current);
return true;
}
}
...
//重写了tryRelease
protected final boolean tryRelease(int releases) {
c = state - releases; //改变同步状态
...
//修改volatile 修饰的状态变量
setState(c);
return free;
}
}
static final class NonfairSync extends Sync {
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
}
....
static final class FairSync extends Sync {
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;
}
}
....
Sync的子类NonfairSync和FairSync都重写了tryAcquire方法
其中NonfairSync的tryAcquire调用父类的nonfairTryAcquire方法,
FairSync则自己重写tryAcquire的逻辑。其中调用hasQueuedPredecessors()判断是否有排队Node,存在则返回false(false会导致当前线程排队等待锁)
ReentrantReadWriteLock
public class ReentrantReadWriteLock
implements ReadWriteLock, java.io.Serializable {
private static final long serialVersionUID = -6992448646407690164L;
/** Inner class providing readlock */
private final ReentrantReadWriteLock.ReadLock readerLock;
/** Inner class providing writelock */
private final ReentrantReadWriteLock.WriteLock writerLock;
/** Performs all synchronization mechanics */
final Sync sync;
/**
* Creates a new {@code ReentrantReadWriteLock} with
* default (nonfair) ordering properties.
*/
public ReentrantReadWriteLock() {
this(false);
}
/**
* Creates a new {@code ReentrantReadWriteLock} with
* the given fairness policy.
*
* @param fair {@code true} if this lock should use a fair ordering policy
*/
public ReentrantReadWriteLock(boolean fair) {
sync = fair ? new FairSync() : new NonfairSync();
readerLock = new ReadLock(this);
writerLock = new WriteLock(this);
}
public ReentrantReadWriteLock.WriteLock writeLock() { return writerLock; }
public ReentrantReadWriteLock.ReadLock readLock() { return readerLock; }
...
ReentrantReadWriteLock实现了ReadWriteLock接口,内部有两个实例对象,ReentrantReadWriteLock.ReadLock readerLock读锁和ReentrantReadWriteLock.WriteLock writerLock写锁。也可以指定是否是公平锁和非公平锁。
ReentrantReadWriteLock内部类:
abstract static class Sync extends AbstractQueuedSynchronizer {
private static final long serialVersionUID = 6317671515068378041L;
static final int SHARED_SHIFT = 16;
//00000000000000010000000000000000
static final int SHARED_UNIT = (1 << SHARED_SHIFT);
//00000000000000001111111111111111
static final int MAX_COUNT = (1 << SHARED_SHIFT) - 1;
//00000000000000001111111111111111
static final int EXCLUSIVE_MASK = (1 << SHARED_SHIFT) - 1;
...
我们先分析读写锁中的这4个int 常量,其实这4个常量的作用就是区分一个int整数的高16位和低16位的,ReentrantReadWriteLock锁还是依托于state变量作为获取锁的标准,那么一个state变量如何区分读锁和写锁呢?答案是通过位运算,高16位表示读锁,低16位表示写锁。
ReentrantReadWriteLock中的读、写锁各个方法的实现都依赖内部类Sync。Sync继承了AQS,覆写了AQS的独占模式方法和共享模式方法。
abstract static class Sync extends AbstractQueuedSynchronizer {
static final int SHARED_SHIFT = 16;
static final int SHARED_UNIT = (1 << SHARED_SHIFT);
static final int MAX_COUNT = (1 << SHARED_SHIFT) - 1;
static final int EXCLUSIVE_MASK = (1 << SHARED_SHIFT) - 1;
//获取当前读锁数量(共享+重入),高16位的数值
static int sharedCount(int c) { return c >>> SHARED_SHIFT; }
//获取当前写锁数量(重入),低16位的数值
static int exclusiveCount(int c) { return c & EXCLUSIVE_MASK; }
Sync() {
readHolds = new ThreadLocalHoldCounter();
setState(getState()); // ensures visibility of readHolds
}
...
}
独占模式
Sync覆写AQS的tryAcquire方法,只允许一个线程获取写锁的同步状态成功
//独占模式
protected final boolean tryAcquire(int acquires) {
Thread current = Thread.currentThread();
int c = getState();
int w = exclusiveCount(c);//获取当前写锁数量
if (c != 0) {
//有其他线程持有读锁,返回false
if (w == 0 || current != getExclusiveOwnerThread())
return false;
if (w + exclusiveCount(acquires) > MAX_COUNT)
throw new Error("Maximum lock count exceeded");
//重入
setState(c + acquires);
return true;
}
//公平锁和非公平锁逻辑 由writerShouldBlock方法来判断
if (writerShouldBlock() ||
!compareAndSetState(c, c + acquires))
return false;
//获取同步状态成功,设置持有锁的线程为当前线程
setExclusiveOwnerThread(current);
return true;
}
-
判断是否有锁,有锁且写锁不存在,证明是读锁,直接返回获取失败。有写锁是不是当前线程,不是返回失败。
-
判断是否超出最大重入范围。
-
重入独占锁,直接设置state值。
-
判断是否是公平锁,非公平锁CAS设置state值,公平锁判断AQS同步队列中是否存在排在该线程之前的的节点,保证先入队的先执行。
Sync覆写AQS的tryRelease方法,定义释放资源的逻辑。由于是独占模式,只会有一个线程同时执行该方法,不会存在并发问题。
//独占模式释放
protected final boolean tryRelease(int releases) {
if (!isHeldExclusively())
throw new IllegalMonitorStateException();
int nextc = getState() - releases;
//判断写锁数量是否为0,0的时候修改持有写锁的线程为null
boolean free = exclusiveCount(nextc) == 0;
if (free)
setExclusiveOwnerThread(null);
setState(nextc);
return free;
}
-
首先判断如果不是持有写锁的线程,调用该方法直接抛出异常
-
state的低16位存储写锁数,没releae一次,低16位减去1,当低16位数值为0的时候,释放写锁成功,修改持有写锁的线程为null
共享模式
Sync覆写AQS的tryAcquireShared方法,定义获取同步状态的逻辑。
//共享模式
protected final int tryAcquireShared(int unused) {
Thread current = Thread.currentThread();
int c = getState();
//其他线程持有写锁,直接返回-1,获取同步状态失败
if (exclusiveCount(c) != 0 &&
getExclusiveOwnerThread() != current)
return -1;
//获取state的高16位数值(读锁数量)
int r = sharedCount(c);
if (!readerShouldBlock() &&是否是公平锁
r < MAX_COUNT &&
compareAndSetState(c, c + SHARED_UNIT)) {
//读锁数量为0,第一次加读锁,设置firstReader为当前线程
if (r == 0) {
firstReader = current;
firstReaderHoldCount = 1;
} else if (firstReader == current) { //读锁重入,如果当前线程是第一个持有该读锁的线程,计数器+1
firstReaderHoldCount++;
} else {
HoldCounter rh = cachedHoldCounter;
if (rh == null || rh.tid != getThreadId(current))
cachedHoldCounter = rh = readHolds.get();
else if (rh.count == 0)
readHolds.set(rh);
rh.count++;
}
//成功获取同步状态,返回一个正整数或者0
return 1;
}
//获取同步状态失败
return fullTryAcquireShared(current);
}
-
存在写锁,如果持有写锁的是当前线程则允许添加读锁,如果持有写锁的是其他线程则不允许添加读锁。
-
调用readerShouldBlock来判断是否公平与非公平。 判断读锁数量不要超过最大值,不能超过16位数值的最大值。
-
存在并发则CAS设置state的值,如果成功则获取读锁的同步状态成功,返回1。
-
如果获取读锁的同步状态失败,调用fullTryAcquireShared方法,循环再次尝试一遍。
Sync覆写AQS的tryReleaseShared方法,定义释放共享锁的逻辑。
//共享模式释放
protected final boolean tryReleaseShared(int unused) {
Thread current = Thread.currentThread();
if (firstReader == current) {
// assert firstReaderHoldCount > 0;
if (firstReaderHoldCount == 1)//如果是首次获取读锁,那么第一次获取读锁释放后就为空了
firstReader = null;
else
firstReaderHoldCount--;
} else {
HoldCounter rh = cachedHoldCounter;
if (rh == null || rh.tid != getThreadId(current))
rh = readHolds.get();
int count = rh.count;
if (count <= 1) { //表示全部释放完毕
readHolds.remove(); //释放完毕,那么久把保存的记录次数remove掉
if (count <= 0)
throw unmatchedUnlockException();
}
--rh.count;
}
for (;;) {
int c = getState();
// nextc 是 state 高 16 位减 1 后的值
int nextc = c - SHARED_UNIT;
if (compareAndSetState(c, nextc)) //CAS设置状态
return nextc == 0; //这个判断如果高 16 位减 1 后的值==0,那么就是读状态和写状态都释放了
}
}
-
修改firstReader和firstReaderHoldCount变量值,移除readHolds记录次数。
-
for循环加CAS修改state的高16位值,当state的高16位为0的时候,释放成功返回true。
CountDownLatch
CountDownLatch是一个同步工具类,有个别名叫计数器,也叫闭锁。它允许一个或多个线程一直等待,直到其他线程的操作执行完后再执行。
public class CountDownLatch {
private static final class Sync extends AbstractQueuedSynchronizer {
private static final long serialVersionUID = 4982264981922014374L;
// 传入初始次数
Sync(int count) {
setState(count);
}
// 获取还剩的次数
int getCount() {
return getState();
}
// 尝试获取共享锁
protected int tryAcquireShared(int acquires) {
// 注意,这里state等于0的时候返回的是1,也就是说count减为0的时候获取总是成功
// state不等于0的时候返回的是-1,也就是count不为0的时候总是要排队
return (getState() == 0) ? 1 : -1;
}
// 尝试释放锁
protected boolean tryReleaseShared(int releases) {
for (;;) {
// state的值
int c = getState();
// 等于0了,则无法再释放了
if (c == 0)
return false;
// 将count的值减1
int nextc = c-1;
// 原子更新state的值
if (compareAndSetState(c, nextc))
// 减为0的时候返回true,这时会唤醒后面排队的线程
return nextc == 0;
}
}
}
public CountDownLatch(int count) {
if (count < 0) throw new IllegalArgumentException("count < 0");
// 初始化 count 值
this.sync = new Sync(count);
}
public void countDown() {
// 调用 releaseShared 每次使同步状态值减 1
sync.releaseShared(1);
}
}
CountDownLatch中只包含了Sync一个内部类,它没有公平/非公平模式,所以它算是一个比较简单的同步器了。
在 CountDownLatch 初始化的时候会有一个初始的同步状态值,这个同步状态值可以理解为放行前的所要执行的线程数,每次调用 countDown 方法时就把同步状态值减 1。
我们来看看await方法:
public void await() throws InterruptedException {
// 共享式检查是否中断,如果中断抛出异常
// 调用 tryAcquireShared 方法尝试获取同步状态,当闭锁内的线程执行完毕后尝试获取成功,直接返回
sync.acquireSharedInterruptibly(1);
}
public final void acquireSharedInterruptibly(int arg)
throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
// 尝试获取锁,如果失败则排队
if (tryAcquireShared(arg) < 0)
doAcquireSharedInterruptibly(arg);
}
private void doAcquireSharedInterruptibly(int arg)
throws InterruptedException {
final Node node = addWaiter(Node.SHARED);// 往同步队列中添加节点
boolean failed = true;
try {
for (;;) {// 一个死循环 跳出循环只有下面两个途径
final Node p = node.predecessor();// 当前线程的前一个节点
if (p == head) {// 如果是首节点
int r = tryAcquireShared(arg);// 这个是不是似曾相识 见上面
if (r >= 0) {
setHeadAndPropagate(node, r);// 处理后续节点
p.next = null; // help GC 这个可以借鉴
failed = false;
return;// 计数值为0 并且为头节点 跳出循环
}
}
if (shouldParkAfterFailedAcquire(p, node) &&
parkAndCheckInterrupt())
throw new InterruptedException();// 响应打断 跳出循环
}
} finally {
if (failed)
cancelAcquire(node);// 如果是打断退出的 则移除同步队列节点
}
}
await 方法会自旋检查同步状态值是否为 0,当不为 0 时会阻塞线程,当为 0 时会直接返回,该方法是支持相应中断的,当线程中断时会抛出异常。因此该方法可以理解为一扇门,只有当指定数量的线程执行完后,才会执行后续的代码。
CyclicBarrier
栅栏类,也叫障碍,似于闭锁,它能阻塞一组线程直到某个事件的发生。栅栏与闭锁的关键区别在于,所有的线程必须同时到达栅栏位置,才能继续执行。
举例:CountDownLatch是线程间的等待,是当前面N个线程全部执行完,第n+1的线程才可以执行!且CountDownLatch只能使用一次;CyclicBarrier是线程内的等待,是当N个线程都执行到一个栅栏状态时,我N个线程才会继续执行!CyclicBarrier可以循环使用;
public class CyclicBarrier {
// parties表示线程数
public CyclicBarrier(int parties) {
this(parties, null); // 调用两个参数的构造方法,即下面的构造方法
}
// parties表示线程数 barrierAction表示栅栏任务,即最后一个线程到达栅栏后执行的任务
public CyclicBarrier(int parties, Runnable barrierAction) {
if (parties <= 0) throw new IllegalArgumentException();
this.parties = parties; // final修饰的 用于下次为count赋值 实现循环功能
this.count = parties; // 等待的数量,栅栏一次循环完成会把parties赋值为count
this.barrierCommand = barrierAction; // 栅栏任务
}
/** The lock for guarding barrier entry */
private final ReentrantLock lock = new ReentrantLock();
/** Condition to wait on until tripped */
private final Condition trip = lock.newCondition();
和计数器类似,实例化的时候指定线程数,也可以加一个额外的任务。
重点是线程中调用的await()方法:
// 如果当前线程在等待过程中阻塞,则抛出InterruptedException
// BrokenBarrierException发生情况较多:①当前线程等待过程中,另外一个线程阻塞或者超时;②栅栏被重置了;③await方法在调用,栅栏被破坏;④由于一个异常导致栅栏任务执行失败
public int await() throws InterruptedException, BrokenBarrierException {
try {
return dowait(false, 0L); //
} catch (TimeoutException toe) { // 超时异常直接抛出错误
throw new Error(toe); // cannot happen
}
}
private int dowait(boolean timed, long nanos)
throws InterruptedException, BrokenBarrierException,
TimeoutException {
final ReentrantLock lock = this.lock; // 利用重入锁保证线程的安全性
lock.lock();
try {
final Generation g = generation; // 栅栏每broken一次,Generation就需要重新生成一个对象
// 如果当前栅栏broken,则抛出BrokenBarrierException异常;
if (g.broken)
throw new BrokenBarrierException();
// 如果当前线程被阻塞,则栅栏被broken,抛出InterruptedException异常
if (Thread.interrupted()) {
breakBarrier();
throw new InterruptedException();
}
// 等待的线程数(count)减1
int index = --count;
if (index == 0) { // tripped 若等待线程数为0,即该线程为最后一个到达栅栏的线程
boolean ranAction = false;
try {
// 当前线程执行栅栏定义的任务
final Runnable command = barrierCommand;
if (command != null)
command.run();
ranAction = true;
nextGeneration(); // 当前栅栏任务完成栅栏功能耗尽,重新定义一个栅栏
return 0;
} finally {
if (!ranAction)
breakBarrier();
}
}
// 如果不是最后一个到达栅栏的线程,则一直循环,直到栅栏被broken,线程被阻塞或者超时
for (;;) {
try {
if (!timed) // timed默认为false 则继续执行
trip.await(); // 线程等待直到满足condition的情况(栅栏被broken/线程阻塞)
else if (nanos > 0L)
nanos = trip.awaitNanos(nanos);
} catch (InterruptedException ie) {
if (g == generation && ! g.broken) {
breakBarrier();
throw ie;
} else {
// We're about to finish waiting even if we had not
// been interrupted, so this interrupt is deemed to
// "belong" to subsequent execution.
Thread.currentThread().interrupt();
}
}
// 如果栅栏被破坏 抛出BrokenBarrierException异常
if (g.broken)
throw new BrokenBarrierException();
// 如果当前栅栏的generation对象不一致,返回等待线程数
if (g != generation)
return index;
// 此处抛出TimeOutException异常 按理来说不会执行,因为timed值为false
if (timed && nanos <= 0L) {
breakBarrier();
throw new TimeoutException();
}
}
} finally {
lock.unlock(); // 释放栅栏的锁,便于其他线程调用栅栏的wati()
}
}
大体流程就是初始化指定线程数,每次调用await()方法等待的数量减少一,并在for循环里面阻塞。支持相应中断的,当线程中断时会抛出异常。当等待的数量为0时新建一个栅栏,同时唤醒所有阻塞的线程,直接返回0。
注意一点,栅栏类没有像其他锁类一样,有内部类继承AbstractQueuedSynchronizer,它时直接实例化了ReentrantLock和Condition。
Semaphore
Semaphore用于管理信号量,在并发编程中,可以控制返访问同步代码的线程数量。
public class Semaphore implements java.io.Serializable {
public Semaphore(int permits) {
sync = new NonfairSync(permits);
}
public Semaphore(int permits, boolean fair) {
sync = fair ? new FairSync(permits) : new NonfairSync(permits);
}
...
}
默认是非公平锁,两个构造方法都必须传int permits值。
这个int值在实例化内部类时,被设置为AQS中的state。
Sync(int permits) {
setState(permits);
}
acquire()获取信号
public void acquire() throws InterruptedException {
sync.acquireSharedInterruptibly(1);
}
实际调用的是AQS中acquireSharedInterruptibly()的方法。
public final void acquireSharedInterruptibly(int arg)
throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
if (tryAcquireShared(arg) < 0)
doAcquireSharedInterruptibly(arg);
}
-
调用tryAcquireShared()方法尝试获取信号。
-
如果没有可用信号,将当前线程加入等待队列并挂起。
tryAcquireShared()方法被Semaphore的内部类NonfairSync和FairSync重写,实现有一些区别。
NonfairSync.tryAcquireShared()
final int nonfairTryAcquireShared(int acquires) {
for (;;) {
int available = getState();
int remaining = available - acquires;
if (remaining < 0 ||
compareAndSetState(available, remaining))
return remaining;
}
}
非公平锁对于信号的获取是直接使用CAS进行尝试的。
FairSync.tryAcquireShared()
protected int tryAcquireShared(int acquires) {
for (;;) {
if (hasQueuedPredecessors())
return -1;
int available = getState();
int remaining = available - acquires;
if (remaining < 0 ||
compareAndSetState(available, remaining))
return remaining;
}
}
公平锁先调用hasQueuedPredecessors()方法,判断队列中是否有等待线程。如果有,直接返回-1,表示没有可用信号。队列中没有等待线程,再使用CAS尝试更新state,获取信号。
acquireSharedInterruptibly()方法中,如果没有可用信号加入队列的方法doAcquireSharedInterruptibly(),这个方法是AQS中的方法,上面没讲,所以这里讲解下:
private void doAcquireSharedInterruptibly(int arg)
throws InterruptedException {
final Node node = addWaiter(Node.SHARED); // 加入等待队列
boolean failed = true;
try {
for (;;) {
final Node p = node.predecessor();
if (p == head) { // 2
int r = tryAcquireShared(arg);//如果前继节点是head,则尝试获取锁
if (r >= 0) {
setHeadAndPropagate(node, r);获取锁成功,设置新head和共享传播(唤醒后继共享节点)
p.next = null; // help GC
failed = false;
return;
}
}
if (shouldParkAfterFailedAcquire(p, node) && // 3
parkAndCheckInterrupt())
throw new InterruptedException();
}
} finally {
if (failed)
cancelAcquire(node);
}
}
-
封装一个Node节点,加入队列尾部。
-
在无限循环中,如果当前节点是头节点,就尝试获取信号,获取到了就设置新的head和唤醒后继共享节点。
-
不是头节点,在经过节点状态判断后,挂起当前线程。
release()释放信号
public void release() {
sync.releaseShared(1);
}
调用的是AQS中的releaseShared()方法。
public final boolean releaseShared(int arg) {
if (tryReleaseShared(arg)) {//释放共享锁
doReleaseShared();//唤醒等待的头部线程
return true;
}
return false;
}
tryReleaseShared()释放,doReleaseShared唤醒等待的头部线程。
至此,AbstractQueuedSynchronizer(AQS)原理及衍生类讲完了,比较多,慢慢看,细节看一遍了解大概就行了,主体流程明白就差不都了。所有的锁都讲完了,底层无非都是CAS+volatile实现,所有锁类都是基于AQS加工。唯一有区别的是栅栏类是唯一一个没有内部类去继承AQS的,而是实例化了重入锁和Conition。