Java AQS

java AbstractQueuedSynchronizer

###以ReentrantLock为例

首先ReentrantLock有公平和非公平模式:NonfairSyncFairSync

FairSync

lock方法的定义:获取锁。

  • 如果锁没有被其他线程获取,则获取锁并立刻返回,把锁的count设为1.
  • 如果锁已经被当前线程持有,则立刻返回,把锁的count +1.
  • 如果锁被其他线程持有,则当前线程会失去被调度的权利,等待被唤醒。

假设有3个线程同时调用ReentrantLock的 lock方法。

image-20180824040623739

结合代码的解释可以参考:https://www.jianshu.com/p/d8eeb31bee5c

Synchronizer 同步器

同步队列,同步节点,同步状态

AbstractQueuedSynchronizer 被用来实现blocking lock或者相关的同步器(semaphores,events)。这个类的基础是 FIFO waiting queue。且用一个原子的int值来表示同步状态。

###子类该怎么定义?

子类应该被定义为一个非public的内部帮助类。

这个类为internal queue提供了各种便利的方法,同时也适用于condition objects。你可以引入这些到你的类里,做一些synchronization mechanics。

独占式同步状态的获取,释放

通过调用同步器的 acquire(int arg)方法来获取到同步状态。

线程获取锁失败后,进入同步队列。

首先,调用tryAcquire方法,尝试获取锁。如果获取失败,则构造同步节点,并通过addWaiter方法将同步节点加入到同步队列的尾部,最后调用acquireQueued方法,使该同步节点以死循环的方式获取到锁,且非中断。只有前置节点为头节点并且tryAcquire成功返回的时候,才会返回。否则就会让线程停止调度,直到unpark或者线程中断。但是,如果前置节点为头结点,但是tryAcquire返回失败,怎么办?

通过同步器的relase方法来释放同步状态。

该方法会先调用tryRelease方法,然后会唤醒其他后续节点,通过调用unparkSuccessor方法,即调用了unpark方法。

同步节点进入同步队列之后,就进入了一个自旋的过程,每个同步节点都在自己观察,当条件满足,就可以从自旋中退出。

###用法:

如果使用这个类作为自定义的synchronozier的基础。

#####1必须实现下面的方法:

tryAcquire : 查询是否可以获取,如果可以则获取。
tryRelease
tryAcquireShared
tryReleaseShared
isHeldExclusively

上面的方法的实现,要尽量简短,不能阻塞

#####2 同步状态的修改(Synchronization state)
getState
setState
compareAndSetState
来修改同步状态,可以保证状态的改变是安全的。

######3 The CORE of exclusive synchronization:

1
2
3
4
5
6
7
8
9
Acquire:
while (!tryAcquire(arg)) {
//enqueue thread if it is not already queued;
//possibly block current thread;
}

Release:
if (tryRelease(arg))
//unblock the first queued thread;

#####Barging Strategy
TODO

#####Examples

举了2个例子:MutexBooleanLatch

Mutext
什么是mutex?Mutual(彼此的) exclusion 的缩写。我们使用mutex去保护临界区,从而防止竞争。进入临界区之前调用 acquire ,离开临界区之前调用release

1
2
3
4
5
6
7
8
9
10
aquire(){
while (!available){
;// busy wait
}
available = false;
}

release() {
available = true;
}

BooleanLatch
BooleanLatch是non-exclusive,所以使用shared aquire 和 release方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
class BooleanLatch {

private static class Sync extends AbstractQueuedSynchronizer {
boolean isSignalled() { return getState() != 0; }

protected int tryAcquireShared(int ignore) {
return isSignalled() ? 1 : -1;
}

protected boolean tryReleaseShared(int ignore) {
setState(1);
return true;
}
}

private final Sync sync = new Sync();
public boolean isSignalled() { return sync.isSignalled(); }
public void signal() { sync.releaseShared(1); }
public void await() throws InterruptedException {
sync.acquireSharedInterruptibly(1);
}

waitStatus 讲解

Latch

作用:A synchronization aid that allows one or more threads to wait until a set of operations being performed in other threads completes.

主要方法:

await() 阻塞等待the count of latch变为0.

CountDown() 给the count of latch -1.