您的位置:首页 > 其它

并发工具类:等待多线程完成的CountDownLatch,和join的区别

2017-05-24 22:00 786 查看

CountDownLatch

CountDownLatch是一个同步辅助类,在完成一组正在其他线程中执行的操作之前,它允许一个或多个线程一直等待。 

CountDownLatch用给定的计数初始化 CountDownLatch。调用countDown()方法,计数减1。在当前计数到达零之前,调用await()方法的线程会一直受阻塞。当前计数到达0之后,会释放所有等待的线程,调用await()的线程的后续调用都将继续执行。这种现象只出现一次,因为CountDownLatch没有提供任何机制去重新设置这个计数值。如果需要重置计数,请考虑使用
CyclicBarrier。 
CountDownLatch是一个通用同步工具,它有很多用途。将计数 1 初始化的 CountDownLatch 用作一个简单的开/关锁存器,或入口:在通过调用 countDown() 的线程打开入口前,所有调用 await()的线程都一直在入口处等待。用 N初始化的 CountDownLatch 可以使一个线程在 N 个线程完成某项操作之前一直等待,或者使其在某项操作完成 N 次之前一直等待。 

看下面的程序

public class CountDownLatchTest {

public static void main(String[] args) throws InterruptedException {

final CountDownLatch cl = new CountDownLatch(2);

new Thread(new Runnable() {

@Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
cl.countDown();
System.out.println("线程1唤醒");
}
}).start();

new Thread(new Runnable() {

@Override
public void run() {
try {
Thread.sleep(1000);
cl.countDown();
System.out.println("线程2唤醒");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();

new Thread(new Runnable() {

@Override
public void run() {
try {
System.out.println("次线程等待被唤醒");
cl.await();
System.out.println("次线程继续执行");

} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();

System.out.println("主线程要等待被唤醒");
//		cl.await(400,TimeUnit.SECONDS);
cl.await();
System.out.println("主线程继续执行");
}

}


 执行结果为:

主线程要等待被唤醒
次线程等待被唤醒
线程1唤醒
线程2唤醒
次线程继续执行
主线程继续执行


另外一个带指定时间的await方法,await(long time, TimeUnit unit): 如果计数还没到0,这个方法等待特定时间后,就会不再阻塞当前线程;如果计数到0了,等待时间还没到,当前线程仍然不再阻塞。

与join的区别

调用thread.join() 方法必须等thread 执行完毕,当前线程才能继续往下执行,而CountDownLatch通过计数器提供了更灵活的控制,只要检测到计数器为0当前线程就可以往下执行而不用 管相应的thread是否执行完毕。
看下面的程序:
public class JoinTest {
public static void main(String[] args) {
Thread a = new Thread(new Runnable() {

@Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程a执行结束");

}
});
Thread b = new Thread(new Runnable() {

@Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("线程b执行结束");

}
});
a.start();
b.start();
try {
a.join();
b.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("主线程结束");
}

}


执行结果:
线程b执行结束
线程a执行结束
主线程结束


join用于让当前执行线程等待join线程执行结束。其实现原理是不停检查join线程是否存活,如果join线程存活则让当前线程wait,代码片段如下,wait(0)表示永远等待下去。
while (isAlive()) {
wait(0);
}
直到join线程中止后,线程的this.notifyAll会被调用,调用notifyAll是在JVM里实现的,所以JDK里看不到
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: