AbstractQueuedSynchronizer 超详细原理解析
LockSupport
也位于包java.util.concurrent.locks
下,基本方法↓
//当前线程放弃CPU,进入等待状态(WAITING),操作系统不再对它进行调度
public static void park()
//直到,有其他线程对它调用了unpark,指定它恢复
public static void unpark(Thread thread)
//指定时间的park变体
public static void parkNanos(long nanos)
public static void parkUntil(long deadline)
//返回线程的blocker对象
public static Object getBlocker(Thread t)
是怎么实现的呢?与CAS方法一样,它们也调用了Unsafe类中的对应方法,Unsafe类最终调用了操作系统的API,从程序员的角度,我们可以认为LockSupport中的这些方法就是基本操作。
demo
import java.util.concurrent.locks.LockSupport;
public class LockSupportDemo {
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread (){
public void run(){
//本线程wait了
LockSupport.park();
System.out.println("exit");
}
};
t.start();
Thread.sleep(1000);
//把线程t恢复
LockSupport.unpark(t);
}
}
AQS (AbstractQueuedSynchronizer)
利用CAS和LockSupport提供的基本方法,就可以用来实现ReentrantLock了。但Java中还有很多其他并发工具,如ReentrantReadWriteLock、Semaphore、CountDownLatch,它们的实现有很多类似的地方,为了复用代码,Java提供了一个抽象类AbstractQueuedSynchronizer,我们简称为AQS,它简化了并发工具的实现。
1.提供了一个int 状态,供子类查询和设置
private volatile int state;
protected final int getState()
protected final void setState(int newState)
protected final boolean compareAndSetState(int expect, int update)
2.当前(持有锁的)线程,提供了方法进行查询和设置
private transient Thread exclusiveOwnerThread;
protected final void setExclusiveOwnerThread(Thread t)
protected final Thread getExclusiveOwnerThread()
3.内部维护了一个等待队列,无阻塞算法进行更新(借助CAS方法实现了)
ReentrantLock内部使用AQS,定义有三个内部类:
//继承AQS 的抽象类,不直接用 ,供后面2个继承
abstract static class Sync extends AbstractQueuedSynchronizer
static final class NonfairSync extends Sync//不公平
static final class FairSync extends Sync//公平
公平和不公平,选一个用,默认不公平↓
private final Sync sync;
//在构造方法中sync被赋值,默认不公平
public ReentrantLock() {
sync = new NonfairSync();
}
ReentrantLock的lock方法
public void lock() {
sync.lock();
}
NonfairSync的lock, 里面调用的都是父类AQS的方法
final void lock() {
if (compareAndSetState(0, 1))
//当前未被锁定,则立即获得锁
setExclusiveOwnerThread(Thread.currentThread());
else
//否则调用acquire(1)获得锁
acquire(1);
}
acquire是AQS中的方法,代码为:
public final void acquire(int arg) {
if (!tryAcquire(arg) &&//这个方法必须被子类重写,AQS里面是抛出异常
//没有得到锁才会运行到&&后面
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();
}
它调用tryAcquire获取锁,tryAcquire必须被子类重写,NonfairSync的实现为:
protected final boolean tryAcquire(int acquires) {
return nonfairTryAcquire(acquires);
}
nonfairTryAcquire是sync中实现的,代码为:
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;
}
}
//如果已被当前线程锁定
else if (current == getExclusiveOwnerThread()) {
//则增加锁定次数
int nextc = c + acquires;
if (nextc < 0) // overflow
throw new Error("Maximum lock count exceeded");
setState(nextc);
//只要状态+1 其他什么都不用干
return true;
}
//没拿到锁
return false;
}
tryAcquire就是尝试获取那个线程独占的变量state.
state如果是0,那么当前还没有线程独占此变量;马上得到锁;
再进行一次判断,看是否是当前线程自己获得的这个锁,第二次进入锁,如果是,那么就增加state的值.否则,返回false
!tryAcquire(arg) && acquireQueued(addWaiter(Node.EXCLUSIVE), arg)
如果tryAcquire返回false,则AQS会调用:
acquireQueued(addWaiter(Node.EXCLUSIVE), arg)
addWaiter会新建一个节点Node
,代表当前线程,然后加入到等待队列尾部,
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;
}
}
//失败,则进行更加完备的入列算法.
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 {
node.prev = t;
if (compareAndSetTail(t, node)) {
t.next = node;
return t;
}
}
}
}
放入等待队列后,调用acquireQueued尝试获得锁,代码为:
final boolean acquireQueued(final Node node, int arg) {
boolean failed = true;
try {
boolean interrupted = false;
//死循环
for (;;) {
//前区
final Node p = node.predecessor();
//如果前区就是头了,再调一次tryAcquire尝试得到锁
if (p == head && tryAcquire(arg)) {
//进这说明成功得到锁了
setHead(node);
p.next = null; // help GC
failed = false;
//返回中断标志
return interrupted;
}
//为了防止CPU不停的执行for循环,消耗CPU资源,
//暂时不可能得到锁就不要继续循环了,Park好了
if (shouldParkAfterFailedAcquire(p, node) &&//是否要Park
parkAndCheckInterrupt())//执行park
//记录中断标志
interrupted = true;
}
} finally {
if (failed)
cancelAcquire(node);
}
}
//park
private final boolean parkAndCheckInterrupt() {
LockSupport.park(this); //将AQS对象自己传入
return Thread.interrupted();
}
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
int ws = pred.waitStatus;
if (ws == Node.SIGNAL) //前一个节点在等待独占性变量释放的通知,所以,当前节点可以阻塞
return true;
if (ws > 0) { //前一个节点处于取消获取独占性变量的状态,所以,可以跳过去,直到没有取消的一个前驱
//返回false
do {
node.prev = pred = pred.prev;
} while (pred.waitStatus > 0);
pred.next = node;
} else {
//将上一个节点的状态设置为signal,返回false,
compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
}
return false;
}
public final void acquire(int arg) {
if (!tryAcquire(arg) &&
//如果 boolean acquireQueued(final Node node, int arg) 返回true
//发生过中断
acquireQueued(addWaiter(Node.EXCLUSIVE), arg))
selfInterrupt();//发生中断才进这里
}
调用selfInterrupt方法设置中断标志位,其代码为:
private static void selfInterrupt() {
Thread.currentThread().interrupt();
}
能获得锁就立即获得,否则加入等待队列,
被唤醒后检查自己是否是第一个等待的线程,如果是且能获得锁,则返回,
否则继续等待,
这个过程中如果发生了中断,lock会记录中断标志位,
但不会提前返回或抛出异常。