ama*_*mal 178 java multithreading countdownlatch countdown
有人可以帮我理解Java CountDownLatch是什么以及何时使用它?
我对这个程序的工作原理并不十分清楚.据我所知,所有三个线程立即启动,每个线程将在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();
}
}
Run Code Online (Sandbox Code Playgroud)
// ------------------------------------------------ -----
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.");
}
}
Run Code Online (Sandbox Code Playgroud)
Nik*_*laB 189
是的,你理解正确.
CountDownLatch在锁存原理工作,主线程将等待门打开.一个线程等待n个线程,在创建时指定CountDownLatch.
任何线程,通常是应用程序的主线程,调用CountDownLatch.await()将等到计数达到零或被另一个线程中断.所有其他线程都需要通过CountDownLatch.countDown()在完成或准备好后调用来倒计时.
一旦计数达到零,等待线程就会继续.其中一个缺点/优点CountDownLatch是它不可重复使用:一旦计数达到零,就不能再使用CountDownLatch了.
编辑:
使用CountDownLatch当一个线程(比如主线程),需要等待一个或多个线程来完成,才能继续处理.
使用的一个典型例子CountDownLatch在Java中是使用服务的体系结构,其中由多个线程提供多种服务,直至所有服务已成功启动应用程序无法启动处理的服务器端核心Java应用程序.
PS OP的问题有一个非常简单的例子,所以我没有包含一个.
Vis*_*ote 42
CountDownLatchJava中的一种同步器允许在开始处理之前Thread 等待一个或多个Threads.
CountDownLatch在锁存原理上工作,线程将一直等到门打开.一个线程等待n创建时指定的线程数CountDownLatch.
例如 final CountDownLatch latch = new CountDownLatch(3);
这里我们将计数器设置为3.
任何线程,通常是应用程序的主线程,调用CountDownLatch.await()将等待计数达到零或被另一个线程中断Thread.所有其他线程都需要通过CountDownLatch.countDown()在完成或准备好工作后调用来倒计时.一旦计数达到零,Thread等待开始运行.
这里计数通过CountDownLatch.countDown()方法递减.
在Thread它调用await()方法将等到初始计数到达零.
要使计数为零,其他线程需要调用该countDown()方法.一旦计数变为零,调用该await()方法的线程将恢复(开始执行).
缺点CountDownLatch是它不可重复使用:一旦计数变为零,它就不再可用了.
vik*_*ait 23
尼古拉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....");
}
}
Run Code Online (Sandbox Code Playgroud)
V J*_* Jo 20
当我们想要等待多个线程完成其任务时使用它.它类似于加入线程.
我们可以在哪里使用CountDownLatch
考虑一个我们有需求的场景,我们有三个线程"A","B"和"C",我们只想在"A"和"B"线程完成或部分完成其任务时启动线程"C".
它可以应用于现实世界的IT场景
考虑一种情况,管理者在开发团队(A和B)之间划分模块,并且他希望将其分配给QA团队,以便仅在两个团队完成任务时进行测试.
public class Manager {
public static void main(String[] args) throws InterruptedException {
CountDownLatch countDownLatch = new CountDownLatch(2);
MyDevTeam teamDevA = new MyDevTeam(countDownLatch, "devA");
MyDevTeam teamDevB = new MyDevTeam(countDownLatch, "devB");
teamDevA.start();
teamDevB.start();
countDownLatch.await();
MyQATeam qa = new MyQATeam();
qa.start();
}
}
class MyDevTeam extends Thread {
CountDownLatch countDownLatch;
public MyDevTeam (CountDownLatch countDownLatch, String name) {
super(name);
this.countDownLatch = countDownLatch;
}
@Override
public void run() {
System.out.println("Task assigned to development team " + Thread.currentThread().getName());
try {
Thread.sleep(2000);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
System.out.println("Task finished by development team Thread.currentThread().getName());
this.countDownLatch.countDown();
}
}
class MyQATeam extends Thread {
@Override
public void run() {
System.out.println("Task assigned to QA team");
try {
Thread.sleep(2000);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
System.out.println("Task finished by QA team");
}
}
Run Code Online (Sandbox Code Playgroud)
上述代码的输出将是:
分配给开发团队devB的任务
分配给开发团队devA的任务
任务由开发团队devB完成
任务由开发团队devA完成
任务分配给QA团队
任务由QA团队完成
这里await()方法等待countdownlatch标志变为0,countDown()方法将countdownlatch标志减1.
JOIN的限制: 以上示例也可以通过JOIN实现,但JOIN不能在两种情况下使用: