1.CountDownLatch
1.1整體架構
- 一個線程或多個線程等待所有線程運行完畢,在繼續執行
- sync 是一個同步器,是 CountDownLatch 的內部類實現
private static final class Sync extends AbstractQueuedSynchronizer {...}
1.2await方法
public void await() throws InterruptedException {
sync.acquireSharedInterruptibly(1);
}
public final void acquireSharedInterruptibly(int arg)
throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
// state爲0的時候不會進入判斷,就會退出
if (tryAcquireShared(arg) < 0)// 嘗試獲取共享鎖,sync子類實現的方法
doAcquireSharedInterruptibly(arg);// AQS實現的方法,會進行阻塞
}
protected int tryAcquireShared(int acquires) {
return (getState() == 0) ? 1 : -1;
}
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) {
// state爲0的時候才能滿足條件,否則就阻塞
int r = tryAcquireShared(arg);
if (r >= 0) {
setHeadAndPropagate(node, r);//設置頭並且喚醒後置節點
p.next = null; // help GC
failed = false;
return;
}
}
if (shouldParkAfterFailedAcquire(p, node) && // 通過pre判斷node是否需要阻塞!
parkAndCheckInterrupt()) // 進行加鎖阻塞!!!!
throw new InterruptedException();
}
} finally {
if (failed)
cancelAcquire(node);
}
}
主要實現是調用的AQS實現的獲取共享鎖方法,
先將節點添加到尾部,然後就一直自旋直到前驅節點是頭節點,就設置頭並且喚醒後直接點
// 帶有超時時間的,最終都會轉化成毫秒
public boolean await(long timeout, TimeUnit unit)
throws InterruptedException {
return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout));
}
1.3countDown
- 每調用一次,都會使 state 減一,底層調用的方法如下:
public void countDown() {
sync.releaseShared(1);
}
// AQS實現的方法
public final boolean releaseShared(int arg) {
if (tryReleaseShared(arg)) { // 釋放節點,cas改變狀態,CountDownLatch的子類sync實現的方法
doReleaseShared(); // 喚醒節點,LockSupport.unpark(s.thread);釋放鎖,AQS實現的方法
return true;
}
return false;
}
// CountDownLatch的子類sync實現的方法
protected boolean tryReleaseShared(int releases) {
// 自旋保證 CAS 一定可以成功
for (;;) {
int c = getState();
// state 已經是 0 了,直接返回 false
if (c == 0)
return false;
// 對 state 進行遞減
int nextc = c-1;
if (compareAndSetState(c, nextc))
return nextc == 0;
}
}
private void doReleaseShared() {
for (;;) {
Node h = head;
if (h != null && h != tail) {
int ws = h.waitStatus;
if (ws == Node.SIGNAL) {// 前繼節點爲此狀態,代表後繼節點正在阻塞
if (!compareAndSetWaitStatus(h, Node.SIGNAL, 0))
continue;
unparkSuccessor(h); // 實際進行解鎖,進行喚醒
}
else if (ws == 0 &&
!compareAndSetWaitStatus(h, 0, Node.PROPAGATE))
continue;
}
// 前面的cas操作都成功就說明釋放節點成功,退出即可
if (h == head)
break;
}
}
第一步:釋放節點,cas改變節點狀態
第二步:喚醒節點,釋放掉鎖
2.Atomic
2.1整體架構
- Atomic 打頭的原子操作類,在高併發場景下,都是線程安全的
private volatile int value;
// 初始化
public AtomicInteger(int initialValue) {
value = initialValue;
}
// 得到當前值
public final int get() {
return value;
}
// 自增 1,並返回自增之前的值
public final int getAndIncrement() {
return unsafe.getAndAddInt(this, valueOffset, 1);
}
// 自減 1,並返回自增之前的值
public final int getAndDecrement() {
return unsafe.getAndAddInt(this, valueOffset, -1);
}