1.JUC下同步器
日常开发会遇到主线程开启多个子线程去并行执行任务,并且主线程需要等待所有子线程执行完后在进行汇总的场景。
同步器出现之前,通常采用Thread.join()方法来实现,join方法不够灵活,JDK大佬就在JUC下新建了几个同步器,底层都是基于AQS实现。
关于AQS可以看看这篇一文带你看懂Java多线程并发,深度剖析AQS源码
下面就针对JUC下三种常见同步器进行简要介绍。
1.1 CountdownLatch 倒计数锁存器
这个同步器相对比较简单,先使用构造方法初始化共享锁数count,然后每次调用countDown()方法, 内部调用sync.releaseShared(1)释放一把锁,锁数减一,直到锁Count等于0则会唤醒之前使用await()方法阻塞的线程。
先看这个tryReleaseShared()
方法
public void countDown() {
sync.releaseShared(1);
}
public final boolean releaseShared(int arg) {
if (tryReleaseShared(arg)) {
signalNext(head);
return true;
}
return false;
}
// 着重看这个方法
protected boolean tryReleaseShared(int releases) {
// Decrement count; signal when transition to zero
for (;;) {
// 当前锁数
int c = getState();
// 锁已经为0 则不在执行减一,避免多线程下重复减一到负数
if (c == 0)
return false;
// 锁减一
int nextc = c - 1;
// CAS操作原子性保证一个线程执行
if (compareAndSetState(c, nextc))
// 如果为0则为true那么将执行signalNext(head)方法
return nextc == 0;
}
}
// h 参数为head 头结点。
private static void signalNext(Node h) {
Node s;
// 如果头结点下一个节点不为空。
if (h != null && (s = h.next) != null && s.status != 0) {
// 取消WAITTING状态 转为唤醒状态
s.getAndUnsetStatus(WAITING);
// 唤醒s节点所对应的线程。
LockSupport