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);
}