1.使用 CountDownLatch ,每个线程完成后都去将计数器减一,最后完成时再来唤醒主线程.
代码示例:
public class testThreadSync3{
public static void main(String[] args) {
final Vector<Integer> list = new Vector<Integer>();
Thread[] threads = new Thread[10];
final CountDownLatch latch = new CountDownLatch(10);
for (int i = 0; i < 10; i++) {
final int num = i;
threads[i] = new Thread(new Runnable() {
public void run() {
try {
Thread.sleep(new Random().nextInt(100));
} catch (InterruptedException e) {
e.printStackTrace();
}
list.add(num);
System.out.print(num + " add.\t");
latch.countDown();
}
});
threads[i].start();
}
try {
latch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(list);;
}
}
输出:
可以看到, 主线程的输出语句会等到所有线程执行完毕再执行.
当主线程调用 await() 方法时, 主线程会等待所有其他线程执行完毕(即 count 减到 0时), 然后主线程再开始执行下面的语句, 这里其他线程的执行不会被阻塞.
但需要注意的是: CountDownLatch 初始化设置count 不可更改,如需要动态设置计数的线程数,可以使用CyclicBarrier.
2. 使用 CyclicBarrier
两者比较:
CountDownLatch | CyclicBarrier | |
---|---|---|
软件包 | java.util.concurrent | java.util.concurrent |
适用情景 | 主线程等待多个工作线程结束 | 多个线程之间互相等待,直到所有线程达到一个障碍点(Barrier point) |
主要方法 | CountDownLatch(int count) (主线程调用)初始化计数CountDownLatch.await (主线程调用)阻塞,直到等待计数为0解除阻塞CountDownLatch.countDown计数减一(工作线程调用) | CyclicBarrier(int parties, Runnable barrierAction) //初始化参与者数量和障碍点执行Action,Action可选。由主线程初始化CyclicBarrier.await() //由参与者调用阻塞,直到所有线程达到屏障点 |
等待结束 | 各线程之间不再互相影响,可以继续做自己的事情。不再执行下一个目标工作。 | 在屏障点达到后,允许所有线程继续执行,达到下一个目标。可以重复使用CyclicBarrier |
异常 | 如果其中一个线程由于中断,错误,或超时导致永久离开屏障点,其他线程也将抛出异常。 | |
其他 | 如果BarrierAction不依赖于任何Party中的所有线程,那么在任何party中的一个线程被释放的时候,可以直接运行这个Action。If(barrier.await()==2){//do action |