웹에서 동시에 정보를 가져오고 버퍼 클래스에서 5 개의 다른 필드를 채우는 5 개의 스레드가있는 애플리케이션을 작성 중입니다.
모든 스레드가 작업을 마쳤을 때 버퍼 데이터의 유효성을 검사하고 데이터베이스에 저장해야합니다.
어떻게해야합니까 (모든 스레드가 작업을 마쳤을 때 알림을 받음)?
답변
내가 취하는 접근 방식은 ExecutorService 를 사용하여 스레드 풀을 관리하는 것입니다.
ExecutorService es = Executors.newCachedThreadPool();
for(int i=0;i<5;i++)
es.execute(new Runnable() { /* your task */ });
es.shutdown();
boolean finished = es.awaitTermination(1, TimeUnit.MINUTES);
// all tasks have finished or the time has been reached.
답변
join
스레드에 할 수 있습니다 . 스레드가 완료 될 때까지 결합이 차단됩니다.
for (Thread thread : threads) {
thread.join();
}
참고 join
가 발생합니다 InterruptedException
. 이런 일이 발생하면 무엇을할지 결정해야합니다 (예 : 불필요한 작업이 수행되지 않도록 다른 스레드를 취소).
답변
다양한 솔루션을 살펴보십시오.
-
join()
API는 Java의 초기 버전에 도입되었습니다. JDK 1.5 릴리스 이후이 동시 패키지에서 몇 가지 좋은 대안을 사용할 수 있습니다 . -
ExecutorService # invokeAll ()
주어진 작업을 실행하고, 모든 것이 완료되면 상태와 결과를 보유한 Future 목록을 반환합니다.
코드 예제는이 관련 SE 질문을 참조하십시오.
-
다른 스레드에서 수행되는 작업 집합이 완료 될 때까지 하나 이상의 스레드가 대기 할 수 있도록하는 동기화 지원입니다.
해, CountDownLatch는 주어진 카운트 초기화됩니다. await 메서드는
countDown()
메서드 호출로 인해 현재 카운트가 0에 도달 할 때까지 차단되며 , 그 후 모든 대기 스레드가 해제되고 이후의 모든 await 호출이 즉시 반환됩니다. 이것은 원샷 현상으로 카운트를 재설정 할 수 없습니다. 카운트를 재설정하는 버전이 필요한 경우 CyclicBarrier 사용을 고려하십시오 .사용법은이 질문을 참조하십시오.
CountDownLatch
-
제출 후 생성 된 모든 Future 객체를 반복 합니다.
ExecutorService
답변
Thread.join()
다른 사람들이 제안한 것 외에도 Java 5는 실행기 프레임 워크를 도입했습니다. 거기에서 당신은 Thread
물체로 작업하지 않습니다 . 대신 Callable
또는 Runnable
개체를 실행자 에게 제출합니다 . 여러 작업을 실행하고 그 결과를 순서에 맞지 않게 반환하는 특수 실행기가 있습니다. 그게 ExecutorCompletionService
:
ExecutorCompletionService executor;
for (..) {
executor.submit(Executors.callable(yourRunnable));
}
그런 다음 반환 take()
할 Future<?>
개체 가 더 이상 없을 때까지 반복적으로 호출 할 수 있으며 이는 모두 완료되었음을 의미합니다.
시나리오에 따라 관련 될 수있는 또 다른 사항은 CyclicBarrier
입니다.
스레드 집합이 모두 서로가 공통 장벽 지점에 도달 할 때까지 기다릴 수있는 동기화 지원입니다. CyclicBarriers는 때때로 서로를 기다려야하는 고정 된 크기의 스레드 파티와 관련된 프로그램에서 유용합니다. 장벽은 대기중인 스레드가 해제 된 후 재사용 될 수 있기 때문에 순환이라고합니다.
답변
또 다른 가능성은 CountDownLatch
간단한 상황에 유용한 객체입니다. 미리 스레드 수를 알고 있기 때문에 관련 개수로 초기화하고 객체의 참조를 각 스레드에 전달합니다.
작업이 완료되면 각 스레드 CountDownLatch.countDown()
는 내부 카운터를 감소시키는 호출 을합니다. 메인 스레드는 다른 모든 것을 시작한 후 CountDownLatch.await()
차단 호출을 수행해야합니다 . 내부 카운터가 0에 도달하면 바로 해제됩니다.
이 개체를 사용 InterruptedException
하면를 던질 수도 있습니다.
답변
다른 스레드가 작업을 완료 할 때까지 Thread Main을 기다리거나 차단합니다.
말했듯 @Ravindra babu
이 다양한 방법으로 달성 할 수 있지만 예를 들어 보여줍니다.
-
java.lang.Thread. join () 이후 : 1.0
public static void joiningThreads() throws InterruptedException { Thread t1 = new Thread( new LatchTask(1, null), "T1" ); Thread t2 = new Thread( new LatchTask(7, null), "T2" ); Thread t3 = new Thread( new LatchTask(5, null), "T3" ); Thread t4 = new Thread( new LatchTask(2, null), "T4" ); // Start all the threads t1.start(); t2.start(); t3.start(); t4.start(); // Wait till all threads completes t1.join(); t2.join(); t3.join(); t4.join(); }
-
java.util.concurrent.CountDownLatch 이후 : 1.5
.countDown()
«래치 그룹의 수를 줄입니다..await()
«await 메서드는 현재 카운트가 0이 될 때까지 차단됩니다.
생성
latchGroupCount = 4
한 경우countDown()
4 번 호출하여 카운트 0을 만들어야합니다. 따라서await()
차단 스레드가 해제됩니다.public static void latchThreads() throws InterruptedException { int latchGroupCount = 4; CountDownLatch latch = new CountDownLatch(latchGroupCount); Thread t1 = new Thread( new LatchTask(1, latch), "T1" ); Thread t2 = new Thread( new LatchTask(7, latch), "T2" ); Thread t3 = new Thread( new LatchTask(5, latch), "T3" ); Thread t4 = new Thread( new LatchTask(2, latch), "T4" ); t1.start(); t2.start(); t3.start(); t4.start(); //latch.countDown(); latch.await(); // block until latchGroupCount is 0. }
Threaded 클래스의 예제 코드 LatchTask
. 접근 방식 사용 joiningThreads();
및 latchThreads();
주요 방법 을 테스트합니다 .
class LatchTask extends Thread {
CountDownLatch latch;
int iterations = 10;
public LatchTask(int iterations, CountDownLatch latch) {
this.iterations = iterations;
this.latch = latch;
}
@Override
public void run() {
String threadName = Thread.currentThread().getName();
System.out.println(threadName + " : Started Task...");
for (int i = 0; i < iterations; i++) {
System.out.println(threadName + " : " + i);
MainThread_Wait_TillWorkerThreadsComplete.sleep(1);
}
System.out.println(threadName + " : Completed Task");
// countDown() « Decrements the count of the latch group.
if(latch != null)
latch.countDown();
}
}
- CyclicBarriers 스레드 집합이 서로 공통 장벽 지점에 도달 할 때까지 모두 대기 할 수 있도록하는 동기화 보조 장치 CyclicBarrier 는 때때로 서로를 기다려야하는 고정 된 크기의 스레드 파티를 포함하는 프로그램에서 유용합니다. 장벽은 대기중인 스레드가 해제 된 후 재사용 될 수 있기 때문에 순환이라고합니다.
CyclicBarrier barrier = new CyclicBarrier(3); barrier.await();
예를 들어이 Concurrent_ParallelNotifyies 클래스 를 참조하십시오 .
-
실행기 프레임 워크 : ExecutorService 를 사용하여 스레드 풀을 만들고 Future를 사용하여 비동기 작업의 진행 상황을 추적 할 수 있습니다 .
-
submit(Runnable)
,submit(Callable)
Future Object를 반환합니다.future.get()
함수 를 사용 하여 작업 스레드가 작업을 완료 할 때까지 주 스레드를 차단할 수 있습니다. -
invokeAll(...)
-각 Callable의 실행 결과를 얻을 수있는 Future 객체 목록을 반환합니다.
-
실행자 프레임 워크와 함께 실행 가능한 인터페이스, 호출 가능한 인터페이스를 사용하는 예제 를 찾으십시오 .
@또한보십시오
답변
당신은
for (Thread t : new Thread[] { th1, th2, th3, th4, th5 })
t.join()
이 for 루프 후에 모든 스레드가 작업을 완료했는지 확인할 수 있습니다.