在 java.util.concurrent 中包含许多的阻塞类:
- ReentrantLock
- Semaphore
- ReentrantReadWriteLock
- CountDownLatch
- SynchronousQueue
- FutureTask
它们都是基于 AQS 构建的。
java8 api 文档: https://docs.oracle.com/javase/8/docs/api/
中文:http://www.matools.com/api/java8
AbstractQueuedSynchronizer(AQS)
AQS 是一个构建锁和同步器的框架。
AQS 解决了在实现同步器时涉及的大量的细节问题,比如等待线程使用 FIFO 队列操作顺序。在不同的同步器中还可以定义一些灵活的标准来判断某个线程是通过还是等待。
/**
* Returns the current value of synchronization state.
* This operation has memory semantics of a {@code volatile} read.
* @return current state value
*/
protected final int getState() {
return state;
}
/**
* Sets the value of synchronization state.
* This operation has memory semantics of a {@code volatile} write.
* @param newState the new state value
*/
protected final void setState(int newState) {
state = newState;
}
/**
* Atomically sets synchronization state to the given updated
* value if the current state value equals the expected value.
* This operation has memory semantics of a {@code volatile} read
* and write.
*
* @param expect the expected value
* @param update the new value
* @return {@code true} if successful. False return indicates that the actual
* value was not equal to the expected value.
*/
protected final boolean compareAndSetState(int expect, int update) {
// See below for intrinsics setup to support this
return unsafe.compareAndSwapInt(this, stateOffset, expect, update);
}
例如当某些子类实现 tryAcquireShared ,返回一个负值,表示获取操作失败;
当返回是 0 时,表示同步器通过独占方式获取;
返回正值,表示同步器通过非独占方式被获取。
ReentrantLock
ReentrantLock 只支持独占的方式获取,因此其实现了 tryAcquire、tryRelease 和 isHeldExclusively
ReentrantLock 将同步的状态用于保存锁获取操作的次数,并且维护一个 owner 变量来保存当前所有者线程的标识符,只有在当前线程刚刚获取到锁,或者正要释放锁的时候,才会修改这个变量。
在 tryRealse 中检查 owner 域,确保当前线程在执行 unlock 操作之前已经获取了锁。
例如 tryAcquire:
/**
* Fair version of tryAcquire. Don't grant access unless
* recursive call or no waiters or is first.
*/
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;
}
当一个线程尝试获取锁时, tryAcquire 将首先检查锁的状态。如果锁未被持有,那么将尝试更新锁的状态表示锁已经被持有了。由于状态可能在检查后被修改,所以使用 compareAndSetState 来原子更新。
如果锁状态表示它已经被持有,并且当前线程是持有者,获取计数递增,如果当前线程不是锁的拥有者,获取锁失败。
Semaphore 和 CountDownLatch
Semaphore 将 AQS 的同步状态用于保存当前可用许可的数量。 首先计算剩余许可的数量,如果没有足够的许可,返回一个值表示获取失败。如果还有剩余的许可,那么 nonfairTryAcquireShared 通过 compareAndSetState 方法降低许可的计数。
如果获取成功,返回一个数表示获取操作成功。
final int nonfairTryAcquireShared(int acquires) {
for (;;) {
int available = getState();
int remaining = available - acquires;
if (remaining < 0 ||
compareAndSetState(available, remaining))
return remaining;
}
}
protected final boolean tryReleaseShared(int releases) {
for (;;) {
int current = getState();
int next = current + releases;
if (next < current) // overflow
throw new Error("Maximum permit count exceeded");
if (compareAndSetState(current, next))
return true;
}
}
CountDownLatch 使用 AQS 的方式和 Semaphore 类似。