java并发编程之美 学习笔记
CountDownLatch
demo
code
public class CountDownLatchTest {
static CountDownLatch countDownLatch = new CountDownLatch(2);
public static void main(String[] args) throws InterruptedException {
System.out.println("main线程执行start....");
ExecutorService executorService = Executors.newFixedThreadPool(2);
executorService.submit(() -> {
try {
//sleep 1秒钟
Thread.sleep(1000);//睡眠1s
} catch (InterruptedException e) {
e.printStackTrace();
}
countDownLatch.countDown();
System.out.println("我是线程1");
});
executorService.submit(() -> {
try {
Thread.sleep(1000);//睡眠1s
} catch (InterruptedException e) {
e.printStackTrace();
}
countDownLatch.countDown();
System.out.println("我是线程2");
});
countDownLatch.await();
System.out.println("main线程执行end....");
executorService.shutdown();
}
}
运行结果
源码分析
CountDownLatch
中定义了一个内部类Sync
,它继承了AbstractQueuedSynchronizer
.
Sync
public class CountDownLatch {
//集成AQS
private static final class Sync extends AbstractQueuedSynchronizer {
private static final long serialVersionUID = 4982264981922014374L;
Sync(int count) {
//设置state
setState(count);
}
int getCount() {
return getState();
}
//申请资源: CountDownLatch当state==0时,表示有资源,直接返回---await()调用;
//入参acquires:无实际意义
protected int tryAcquireShared(int acquires) {
//判断当前state == 0
return (getState() == 0) ? 1 : -1;
}
//释放资源 --- countdown()方法调用
protected boolean tryReleaseShared(int releases) {
for (;;) {
int c = getState();
//如果当前state == 0,表示无法再次释放,return false
if (c == 0)
return false;
int nextc = c-1;
//cas操作,将state自减1,
if (compareAndSetState(c, nextc))
//如果cas操作成功,且cas操作完成后,state为0,则表示释放资源成功
//接下来进行,“唤醒”阻塞线程操作。
return nextc == 0;
}
}
}
}
构造函数()
public class CountDownLatch {
private final Sync sync;
public CountDownLatch(int count) {
if (count < 0) throw new IllegalArgumentException("count < 0");
//调用Sync的构造函数,设置state初始值为count,
this.sync = new Sync(count);
}
}
await()
//1.CountDownLatch#await()
public void await() throws InterruptedException {
//2.
sync.acquireSharedInterruptibly(1);
}
//2.AQS#acquireSharedInterruptibly
public final void acquireSharedInterruptibly(int arg)
throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
if (tryAcquireShared(arg) < 0) //3
//4. 将当前线程添加至“阻塞队列”中
doAcquireSharedInterruptibly(arg);
}
//3.CountDownLatch.Sync#tryAcquireShared
//判断当前state == 0
//state == 0 : 返回1, 表示有资源可用,await()操作直接返回
//state != 0 : 返回-1,表示资源需等待,需要将当前线程添加至阻塞队列
protected int tryAcquireShared(int acquires) {
return (getState() == 0) ? 1 : -1;
}
countDown()
//1.CountDownLatch#countDown()
public void countDown() {
//2
sync.releaseShared(1);
}
//2.AQS#releaseShared
public final boolean releaseShared(int arg) {
if (tryReleaseShared(arg)) { //3.
//4."唤醒"阻塞线程
doReleaseShared();
return true;
}
return false;
}
//3.CountDownLatch.Sync#tryReleaseShared
// cas操作,当前state--,
protected boolean tryReleaseShared(int releases) {
for (;;) {
int c = getState();
//如果当前state==0,返回false
if (c == 0)
return false;
int nextc = c-1;
//cas操作,state自减1,如果操作失败,重新执行for-each循环
if (compareAndSetState(c, nextc))
//cas操作成功后的state == 0, 则表示资源可用, 唤醒阻塞队列
//state != 0 , do nothing
return nextc == 0;
}
}
注意
CountDownLatch 的计数器是
一次性
的,也就是等到计数器值变为0 后,
再调用 CountDownLatch 的 await 和 countdown 方法都会立刻返回,这就起不到线程同步的效果了 。