CountDownLatch는 Java 멀티 스레딩에서 어떻게 사용됩니까?
누군가 Java CountDownLatch
가 무엇 이며 언제 사용 하는지 이해하도록 도와 줄 수 있습니까 ?
이 프로그램의 작동 방식에 대한 명확한 아이디어가 없습니다. 세 개의 스레드가 모두 한 번에 시작되고 각 스레드가 3000ms 후에 CountDownLatch를 호출한다는 것을 이해합니다. 카운트 다운은 하나씩 감소합니다. 래치가 0이되면 프로그램은 "Completed"를 인쇄합니다. 어쩌면 내가 이해 한 방식이 틀릴 수도 있습니다.
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.");
}
}
예, 당신은 올바르게 이해했습니다. CountDownLatch
래치 원리로 작동하면 주 스레드는 게이트가 열릴 때까지 기다립니다. 에 대한 하나 개의 스레드 대기 n 개의 을 만드는 동안 지정된 스레드 CountDownLatch
.
Any thread, usually the main thread of the application, which calls CountDownLatch.await()
will wait until count reaches zero or it's interrupted by another thread. All other threads are required to count down by calling CountDownLatch.countDown()
once they are completed or ready.
As soon as count reaches zero, the waiting thread continues. One of the disadvantages/advantages of CountDownLatch
is that it's not reusable: once count reaches zero you cannot use CountDownLatch
any more.
Edit:
Use CountDownLatch
when one thread (like the main thread) requires to wait for one or more threads to complete, before it can continue processing.
CountDownLatch
Java에서 사용하는 전형적인 예 는 서비스 아키텍처를 사용하는 서버 측 핵심 Java 응용 프로그램으로, 여러 스레드에서 여러 서비스를 제공하고 모든 서비스가 성공적으로 시작될 때까지 응용 프로그램이 처리를 시작할 수 없습니다.
PS OP의 질문은 꽤 간단한 예가 있으므로 포함하지 않았습니다.
CountDownLatch
Java에서 처리기 시작하기 전에 Thread
하나 이상의 Thread
s 를 기다릴 수있는 동기화 프로그램 유형입니다 .
CountDownLatch
래치 원리로 작동하면 게이트가 열릴 때까지 스레드가 대기합니다. 하나의 스레드는 n
작성하는 동안 지정된 스레드 수를 기다립니다 CountDownLatch
.
예 : final CountDownLatch latch = new CountDownLatch(3);
여기서 카운터를 3으로 설정했습니다.
모든 스레드 호출 응용 프로그램의 보통 메인 쓰레드, CountDownLatch.await()
카운트 0에 도달하거나 다른 의해 중단 될 때까지 기다립니다 Thread
. 다른 모든 스레드는 CountDownLatch.countDown()
완료되거나 작업 준비가되면 호출하여 카운트 다운을 수행해야합니다 . 카운트가 0에 도달하면 Thread
대기가 시작됩니다.
여기서 카운트는 CountDownLatch.countDown()
방법에 따라 감소합니다 .
Thread
부르는있는 await()
방법은 제로 초기 카운트에 도달 할 때까지 기다립니다.
다른 스레드 수를 0으로 만들려면 countDown()
메서드 를 호출해야합니다 . 카운트가 0이되면 await()
메소드 를 호출 한 스레드 가 재개됩니다 (실행 시작).
단점은 CountDownLatch
재사용 할 수 없다는 것입니다. 카운트가 0이되면 더 이상 사용할 수 없습니다.
NikolaB는 그것을 잘 설명했지만 예제는 이해하는 데 도움이 될 것이므로 간단한 예제가 있습니다.
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....");
}
}
하나 이상의 스레드가 작업을 완료하기를 기다릴 때 사용됩니다. 스레드에서 조인하는 것과 비슷합니다.
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");
}
}
위 코드의 출력은 다음과 같습니다.
개발 팀 devB에 할당 된 작업
개발 팀 devA에 할당 된 작업
개발 팀 devB에 의해 완료된 작업
개발 팀 devA에 의해 완료된 작업
품질 보증팀에 할당 된 작업
품질 관리팀에서 작업 완료
여기서 await () 메소드는 countdownlatch 플래그가 0이 될 때까지 대기하며 countDown () 메소드는 countdownlatch 플래그를 1 씩 감소시킵니다.
JOIN의 제한 : 위의 예는 JOIN으로 도 달성 할 수 있지만 JOIN은 두 가지 시나리오에서 사용할 수 없습니다.
- Thread 클래스 대신 ExecutorService를 사용하여 스레드를 만드는 경우
- 개발이 80 % 작업을 완료하자마자 Manager가 QA 팀에게 코드를 전달하려는 위의 예를 수정하십시오. CountDownLatch를 사용하면 부분 실행을 위해 다른 스레드를 기다리는 데 사용할 수있는 구현을 수정할 수 있습니다.
이와 같은 것을 사용하는 좋은 예는 Java Simple Serial Connector를 사용하여 직렬 포트에 액세스하는 것입니다. 일반적으로 포트에 무언가를 쓰고 다른 스레드에서는 비동기 적으로 장치가 SerialPortEventListener에서 응답합니다. 일반적으로 포트에 쓴 후 응답을 기다리기 위해 일시 중지하려고합니다. 이 시나리오에서 스레드 잠금을 수동으로 처리하는 것은 매우 까다 롭지 만 Countdownlatch를 사용하는 것은 쉽습니다. 당신이 다른 방법으로 할 수 있다고 생각하기 전에, 당신이 결코 생각하지 않은 경쟁 조건에주의하십시오!
의사 코드 :
CountDownLatch latch; void writeData() { latch = new CountDownLatch(1); serialPort.writeBytes(sb.toString().getBytes()) try { latch.await(4, TimeUnit.SECONDS); } catch (InterruptedException e) { } } class SerialPortReader implements SerialPortEventListener { public void serialEvent(SerialPortEvent event) { if(event.isRXCHAR()){//If data is available byte buffer[] = serialPort.readBytes(event.getEventValue()); latch.countDown(); } } }
CoundDownLatch를 사용하면 다른 모든 스레드가 실행으로 완료 될 때까지 스레드를 대기시킬 수 있습니다.
의사 코드는 다음과 같습니다.
// Main thread starts
// Create CountDownLatch for N threads
// Create and start N threads
// Main thread waits on latch
// N threads completes there tasks are returns
// Main thread resume execution
atch.countDown () 호출 후 디버그를 추가하면 동작을 더 잘 이해하는 데 도움이 될 수 있습니다.
latch.countDown();
System.out.println("DONE "+this.latch); // Add this debug
출력에 카운트가 감소한 것으로 표시됩니다. 이 'count'는 실제로 countDown ()이 호출 되지 않았기 때문에 시작한 Runnable 태스크 (프로세서 오브젝트)의 수 이며, 이에 따라 atch.await ()에 대한 호출에서 기본 스레드가 차단됩니다.
DONE java.util.concurrent.CountDownLatch@70e69696[Count = 2]
DONE java.util.concurrent.CountDownLatch@70e69696[Count = 1]
DONE java.util.concurrent.CountDownLatch@70e69696[Count = 0]
CountDownLatch 에 대한 오라클 문서에서 :
하나 이상의 스레드가 다른 스레드에서 수행중인 작업 세트가 완료 될 때까지 대기 할 수 있도록하는 동기화 지원.
CountDownLatch
주어진 카운트로 A 가 초기화됩니다. await
현재 카운트가 도달의 호출에 의한 제로까지 차단 방법 countDown()
모든 대기중인 스레드가 해제 된 후에있어서, 즉시 AWAIT 복귀 후속 호출. 이것은 일회성 현상이므로 카운트를 재설정 할 수 없습니다.
CountDownLatch는 다목적 동기화 도구이며 다양한 목적으로 사용될 수 있습니다.
A는 CountDownLatch
이 호출 스레드 카운트에 의해 개방 될 때까지 대기 게이트 AWAIT 호출 모든 스레드 () : 래치 온 / 오프 간단한 게이트 또는 하나의 카운트가 게재으로 초기화.
CountDownLatch
N 초기화는 N 스레드가 어떤 행동을 완료, 또는 어떤 조치가 N 회 완료 될 때까지 하나 개의 스레드가 대기를 만들기 위해 사용할 수 있습니다.
public void await()
throws InterruptedException
스레드가 중단되지 않는 한 래치가 0으로 카운트 다운 될 때까지 현재 스레드가 대기하도록합니다.
현재 카운트가 0이면이 메소드는 즉시 리턴합니다.
public void countDown()
개수가 0에 도달하면 래치의 개수를 감소시켜 모든 대기 스레드를 해제합니다.
현재 카운트가 0보다 크면 감소합니다. 새 개수가 0이면 모든 대기중인 스레드가 스레드 예약 목적으로 다시 활성화됩니다.
귀하의 예에 대한 설명.
latch
변수에 대해 개수를 3으로 설정했습니다CountDownLatch latch = new CountDownLatch(3);
이 공유
latch
를 Worker 스레드에 전달했습니다 .Processor
- 에 세 개의
Runnable
사례Processor
가 제출되었습니다ExecutorService
executor
메인 스레드 (
App
)가 아래 명령문으로 카운트가 0이되기를 기다리고 있습니다.latch.await();
Processor
스레드가 3 초 동안 휴면 한 후 다음과 같이 카운트 값이 감소합니다.latch.countDown()
첫 번째
Process
인스턴스는로 인해 완료 후 래치 수를 2로 변경합니다latch.countDown()
.두 번째
Process
인스턴스는로 인해 완료 후 래치 수를 1로 변경합니다latch.countDown()
.세 번째
Process
인스턴스는로 인해 완료 후 래치 카운트를 0으로 변경합니다latch.countDown()
.래치의 카운트가 0이면 주 스레드
App
가 나옵니다.await
앱 프로그램은 이제이 출력을 인쇄합니다.
Completed
Java Doc 의이 예제 는 개념을 명확하게 이해하는 데 도움이되었습니다.
class Driver { // ...
void main() throws InterruptedException {
CountDownLatch startSignal = new CountDownLatch(1);
CountDownLatch doneSignal = new CountDownLatch(N);
for (int i = 0; i < N; ++i) // create and start threads
new Thread(new Worker(startSignal, doneSignal)).start();
doSomethingElse(); // don't let run yet
startSignal.countDown(); // let all threads proceed
doSomethingElse();
doneSignal.await(); // wait for all to finish
}
}
class Worker implements Runnable {
private final CountDownLatch startSignal;
private final CountDownLatch doneSignal;
Worker(CountDownLatch startSignal, CountDownLatch doneSignal) {
this.startSignal = startSignal;
this.doneSignal = doneSignal;
}
public void run() {
try {
startSignal.await();
doWork();
doneSignal.countDown();
} catch (InterruptedException ex) {} // return;
}
void doWork() { ... }
}
시각적 해석 :
분명히 CountDownLatch
하나의 스레드 (here Driver
)가 실행중인 스레드 (여기 Worker
)가 실행될 때까지 기다릴 수 있습니다.
As mentioned in JavaDoc (https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/CountDownLatch.html), CountDownLatch is a synchronization aid, introduced in Java 5. Here the synchronization does not mean restricting access to a critical section. But rather sequencing actions of different threads. The type of synchronization achieved through CountDownLatch is similar to that of Join. Assume that there is a thread "M" which needs to wait for other worker threads "T1", "T2", "T3" to complete its tasks Prior to Java 1.5, the way this can be done is, M running the following code
T1.join();
T2.join();
T3.join();
The above code makes sure that thread M resumes its work after T1, T2, T3 completes its work. T1, T2, T3 can complete their work in any order. The same can be achieved through CountDownLatch, where T1,T2, T3 and thread M share same CountDownLatch object.
"M" requests : countDownLatch.await();
where as "T1","T2","T3" does countDownLatch.countdown();
One disadvantage with the join method is that M has to know about T1, T2, T3. If there is a new worker thread T4 added later, then M has to be aware of it too. This can be avoided with CountDownLatch. After implementation the sequence of action would be [T1,T2,T3](the order of T1,T2,T3 could be anyway) -> [M]
Best real time Example for countDownLatch explained in this link CountDownLatchExample
package practice;
import java.util.concurrent.CountDownLatch;
public class CountDownLatchExample {
public static void main(String[] args) throws InterruptedException {
CountDownLatch c= new CountDownLatch(3); // need to decrements the count (3) to zero by calling countDown() method so that main thread will wake up after calling await() method
Task t = new Task(c);
Task t1 = new Task(c);
Task t2 = new Task(c);
t.start();
t1.start();
t2.start();
c.await(); // when count becomes zero main thread will wake up
System.out.println("This will print after count down latch count become zero");
}
}
class Task extends Thread{
CountDownLatch c;
public Task(CountDownLatch c) {
this.c = c;
}
@Override
public void run() {
try {
System.out.println(Thread.currentThread().getName());
Thread.sleep(1000);
c.countDown(); // each thread decrement the count by one
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
참고URL : https://stackoverflow.com/questions/17827022/how-is-countdownlatch-used-in-java-multithreading
'Programming' 카테고리의 다른 글
렌즈, fclabels, 데이터 접근 자-구조 접근 및 돌연변이를위한 라이브러리가 더 좋습니다 (0) | 2020.05.25 |
---|---|
알림 시스템 구축 [폐쇄] (0) | 2020.05.25 |
Path.Combine이 Path.DirectorySeparatorChar로 시작하는 파일 이름을 올바르게 연결하지 않는 이유는 무엇입니까? (0) | 2020.05.24 |
C # 메서드 이름에 "Try"는 언제 사용됩니까? (0) | 2020.05.24 |
Java SE 8에 페어 또는 튜플이 있습니까? (0) | 2020.05.24 |