上篇文章:java多线程解说【拾肆】_线程池
从JDK5开始,java为我们的多线程开发提供了多种并发工具,最常用的是如下三个:
1.CountDownLatch
2.CyclicBarrier
3.Semaphore
本文先介绍一下CountDownLatch:
CountDownLatch
CountDownLatch可以在如下的场景使用:当一个线程需要在另外若干个线程执行完毕后再执行时。当然我们也可以使用join()方法来实现,但是这需要去逐个线程等待,而且各个线程是串行运行的。CountDownLatch的实现是等待一个信号量count,每当线程执行一次CountDownLatch.countDown()方法时,CountDownLatch就将count-1,直到count为0时,将唤醒执行CountDownLatch.await()处的线程。
一个例子
public class TestCountDownLatch {
private static CountDownLatch countDownLatch = new CountDownLatch(5);
public static void main(String[] args) {
Thread waitThread = new Thread(){
@Override
public void run() {
try {
System.out.println("waitThread线程在等待执行");
TestCountDownLatch.countDownLatch.await();
System.out.println("5个线程执行完毕,waitThread执行");
} catch (Exception e) {
e.printStackTrace();
}
}
};
waitThread.start();
for (int i = 0; i < 5; i++) {
Thread thread = new Thread(){
@Override
public void run() {
try {
TestCountDownLatch.countDownLatch.countDown();
System.out.println("线程"+this.getName()+"准备就绪");
} catch (Exception e) {
e.printStackTrace();
}
}
};
thread.start();
}
}
}
上述代码执行的结果为:
线程Thread-1准备就绪
waitThread线程在等待执行
线程Thread-2准备就绪
线程Thread-4准备就绪
线程Thread-3准备就绪
线程Thread-5准备就绪
5个线程执行完毕,waitThread执行
常用API
// 使当前线程在锁存器倒计数至零之前一直等待,除非线程被中断。
void await()
// 使当前线程在锁存器倒计数至零之前一直等待,除非线程被中断或超出了指定的等待时间。
boolean await(long timeout, TimeUnit unit)
// 递减锁存器的计数,如果计数到达零,则释放所有等待的线程。
void countDown()
// 返回当前计数。
long getCount()
实现分析
CountDownLatch内部维护了一个Sync对象,Sync继承于AbstractQueuedSynchronizer类(AQS)。在AQS中维护了一个private volatile long类型的变量state。对于CountDownLatch而言,锁计数器即通过state实现的。CountDownLatch中的getCount()最终是调用AQS中的getState(),返回的state对象即锁计数器。
CountDownLatch的await()实际上就是尝试去获取共享锁,获取不到则一直等待,获取到的条件就是state=0;而countDown()实际上调用releaseShared(1),让state-1。
这里需要注意的是,CountDownLatch只能使用一次,也就是说当count=0后就无法继续使用了。那么如果我们想重复使用该怎么办,请看下一文:
java多线程解说【拾陆】_并发工具类:CyclicBarrier