问题
有人可以帮我理解JavaCountDownLatch
是什么以及何时使用它?
我对这个程序的工作原理并不十分清楚。据我所知,所有三个线程一次启动,每个线程将在3000ms后调用CountDownLatch。所以倒计时将逐一减少。锁存器变为零后,程序打印"已完成"。也许我理解的方式不正确。
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
class Processor implements Runnable {
private CountDownLatch latch;
public Processor(CountDownLatch latch) {
this.latch = latch;
}
public void run() {
System.out.println("Started.");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
latch.countDown();
}
}
// ------------------------------------------------ -----
public class App {
public static void main(String[] args) {
CountDownLatch latch = new CountDownLatch(3); // coundown from 3 to 0
ExecutorService executor = Executors.newFixedThreadPool(3); // 3 Threads in pool
for(int i=0; i < 3; i++) {
executor.submit(new Processor(latch)); // ref to latch. each time call new Processes latch will count down by 1
}
try {
latch.await(); // wait until latch counted down to 0
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Completed.");
}
}
#1 热门回答(160 赞)
是的,你理解正确。在闩锁原理中,主线程将一直等到门打开。一个线程等待在创建CountDownLatch
时指定的fornthreads。
任何线程,通常是应用程序的主线程,调用CountDownLatch.await()
将等到计数达到零或被另一个线程中断。所有其他线程都需要通过调用CountDownLatch.countDown()
来倒计时,因为它们已完成或准备就绪。
一旦计数达到零,等待线程就会继续。 CountDownLatch
的一个缺点/优点是它不可重复使用:一旦计数达到零,你就不能再使用CountDownLatch
了。
编辑:
当一个线程(如主线程)需要等待一个或多个线程完成时才使用CountDownLatch
,然后才能继续处理。
在Java中使用CountDownLatch
的经典示例是服务器端核心Java应用程序,它使用服务体系结构,其中多个服务由多个线程提供,并且应用程序无法在所有服务成功启动之前开始处理。
附: OP的问题有一个非常简单的例子,所以我没有包含一个。
#2 热门回答(32 赞)
CountDownLatch
in Java是一种同步器,允许oneThread
在开始处理之前等待一个或多个Thread
。
CountDownLatch
件在锁存原理上,线程将一直等到门打开。一个线程在创建CountDownLatch
时等待指定的n
个线程数。
e.g.final CountDownLatch latch = new CountDownLatch(3);
这里我们将计数器设置为3。
任何线程,通常是应用程序的主线程,调用CountDownLatch.await()
将等到计数达到零或被另一个Thread
中断。所有其他线程都需要通过调用CountDownLatch.countDown()
来完成倒计时,因为它们已完成或准备就绪。一旦计数达到零,Thread
awa就开始运行。
这里的计数是通过CountDownLatch.countDown()
方法减少的。
调用await()
方法的Thread
将等到初始计数达到零。
要使计数为零,其他线程需要调用thecountDown()
方法。一旦计数变为零,调用await()
方法的线程将恢复(开始执行)。
CountDownLatch
的缺点是它不可重复使用:一旦计数变为零,它就不再可用了。
#3 热门回答(18 赞)
尼古拉B解释得非常好,但是例子有助于理解,所以这里有一个简单的例子......
import java.util.concurrent.*;
public class CountDownLatchExample {
public static class ProcessThread implements Runnable {
CountDownLatch latch;
long workDuration;
String name;
public ProcessThread(String name, CountDownLatch latch, long duration){
this.name= name;
this.latch = latch;
this.workDuration = duration;
}
public void run() {
try {
System.out.println(name +" Processing Something for "+ workDuration/1000 + " Seconds");
Thread.sleep(workDuration);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(name+ "completed its works");
//when task finished.. count down the latch count...
// basically this is same as calling lock object notify(), and object here is latch
latch.countDown();
}
}
public static void main(String[] args) {
// Parent thread creating a latch object
CountDownLatch latch = new CountDownLatch(3);
new Thread(new ProcessThread("Worker1",latch, 2000)).start(); // time in millis.. 2 secs
new Thread(new ProcessThread("Worker2",latch, 6000)).start();//6 secs
new Thread(new ProcessThread("Worker3",latch, 4000)).start();//4 secs
System.out.println("waiting for Children processes to complete....");
try {
//current thread will get notified if all chidren's are done
// and thread will resume from wait() mode.
latch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("All Process Completed....");
System.out.println("Parent Thread Resuming work....");
}
}