CountDownLatch
帮助一个或多个线程等待,直到其他线程中执行的操作都完成
CountDownLatch与给定数初始化。await直到当前计数达到零的countDown()方法调用,之后,所有等待的线程,释放任何后续的调用await立即返回。
CountDownLatch是一种通用的同步工具,可以用于许多用途。
CountDownLatch latch=new CountDownLatch(2);
System.out.println("开始时间"+new Date());
Thread thread1 = new Thread(new Runnable() {
@Override
public void run() {
// TODO 自动生成的方法存根
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
System.out.println("1号打螺丝完成时间"+new Date());
System.out.println(" 我是1号程序员开始拧螺丝 ");
latch.countDown();
}
});
Thread thread2 = new Thread(new Runnable() {
@Override
public void run() {
// TODO 自动生成的方法存根
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
// TODO 自动生成的 catch 块
e.printStackTrace();
}
System.out.println("2号打螺丝完成时间"+new Date());
System.out.println(" 我是2号程序员开始拧螺丝 ");
latch.countDown();
}
});
thread1.start();
thread2.start();
latch.await();
System.out.println("结束时间"+new Date());
打印结果
在CountDownLatch类中,维护了一个内部类Sync,他继承了AQS,CoutDownLatch通过维护这个Sync,来实现所有功能
private static final class Sync extends AbstractQueuedSynchronizer {
private static final long serialVersionUID = 4982264981922014374L;
Sync(int count) {
setState(count);
}
int getCount() {
return getState();
}
protected int tryAcquireShared(int acquires) {
return (getState() == 0) ? 1 : -1;
}
protected boolean tryReleaseShared(int releases) {
// Decrement count; signal when transition to zero
for (;;) {
int c = getState();
if (c == 0)
return false;
int nextc = c-1;
if (compareAndSetState(c, nextc))
return nextc == 0;
}
}
}
构造方法
内部通过Sync这个类,来设置计数器的值
public CountDownLatch(int count) {
if (count < 0) throw new IllegalArgumentException("count < 0");
this.sync = new Sync(count);
}
那这个state又是在哪呢?
看源码,是在AQS中维护了一个state,所以,实际上CountDownLatch的计数器,实际上就是AQS中的state
调用countDown方法,该方法委托给AQS来执行,先调用sync重写的tryRealeaseShared方法,
protected boolean tryReleaseShared(int releases) {
// Decrement count; signal when transition to zero
for (;;) {
int c = getState();
if (c == 0)
return false;
int nextc = c-1;
if (compareAndSetState(c, nextc))
return nextc == 0;
}
}
true:此次释放资源的行为可能会让一个阻塞等待中的线程被唤醒
返回结果之后,实际通过doReleaseShared()方法来唤醒同步队列中的后续线程
如果返回false,则什么也不做
public void countDown() {
sync.releaseShared(1); //调用aqs的方法
}
// AQS的方法 实际调用的方法
public final boolean releaseShared(int arg) {
// tryReleaseShared(arg)实际走的是CountDownLatch下Sync这个内部类
if (tryReleaseShared(arg)) {
doReleaseShared();
return true;
}
return false;
}
await()让调用它的线程进行等待,直到所有CountDownLatch中的任务执行完成后,继续执行
可以看到实际走的是AQS的acquireSharedInterruptibly这个方法,
在这个方法中会通过Thread 的方法,进而判断线程是否中断,如果已经中断,直接抛出异常,如果在等待过程中,收到终端型哈哈,也会抛出中断异常,
所以await()会响应中断
protected int tryAcquireShared(int acquires) {
return (getState() == 0) ? 1 : -1;
}
public void await() throws InterruptedException {
sync.acquireSharedInterruptibly(1);
}
public final void acquireSharedInterruptibly(int arg)
throws InterruptedException {
if (Thread.interrupted())
throw new InterruptedException();
if (tryAcquireShared(arg) < 0)
doAcquireSharedInterruptibly(arg);
}
CountDownLatch又和join有点相似
但事实上,内部实现还是有区别的
countDownLatch内部是通过AQS的双向链表,来维护等待线程,
Thread.join()是通过wait()阻塞当前线程,不断检查调用线程是否执行完毕,如果执行完毕会调用notifyAll()方法来唤醒当前线程。