다수의 스레드가 완료될 때까지 기다리는 방법
모든 스레드 프로세스가 완료될 때까지 대기하는 방법은 무엇입니까?예를 들어 다음과 같이 합시다.
public class DoSomethingInAThread implements Runnable{
public static void main(String[] args) {
for (int n=0; n<1000; n++) {
Thread t = new Thread(new DoSomethingInAThread());
t.start();
}
// wait for all threads' run() methods to complete before continuing
}
public void run() {
// do something here
}
}
이 하여 '''로 할 수 요?main()
정지합니다.run()
합니다!★★★★★★★★★★★★★★★★★★!
모든 스레드를 배열에 배치하고 모든 스레드를 시작하여 루프를 만듭니다.
for(i = 0; i < threads.length; i++)
threads[i].join();
각 결합은 해당 나사산이 완료될 때까지 차단됩니다.스레드는 가입 순서와는 다른 순서로 완료될 수 있지만 문제가 되지 않습니다.루프가 종료되면 모든 스레드가 완료됩니다.
한 가지 방법으로는 다음 중 하나를 만들 수 있습니다.List
Thread
각 스레드를 작성 및 실행하여 목록에 추가합니다. 것이되면, 해, 「 」 「 」 「 」 「 」 「 」 「 」join()
실행이 어떤 의 실행이 끝날 스레드가 된다는 것만.스레드 실행이 어떤 순서로 완료되든 상관없습니다.두 번째 루프의 실행이 완료될 때까지 모든 스레드가 완료된다는 것만 알면 됩니다.
보다 나은 방법은 Executor Service 및 관련 방법을 사용하는 것입니다.
List<Callable> callables = ... // assemble list of Callables here
// Like Runnable but can return a value
ExecutorService execSvc = Executors.newCachedThreadPool();
List<Future<?>> results = execSvc.invokeAll(callables);
// Note: You may not care about the return values, in which case don't
// bother saving them
이그제큐티브 서비스(및 Java 5의 동시성 유틸리티의 모든 새로운 것)를 사용하는 것은 매우 유연하며, 위의 예에서는 거의 표면에 흠집이 나지 않습니다.
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
public class DoSomethingInAThread implements Runnable
{
public static void main(String[] args) throws ExecutionException, InterruptedException
{
//limit the number of actual threads
int poolSize = 10;
ExecutorService service = Executors.newFixedThreadPool(poolSize);
List<Future<Runnable>> futures = new ArrayList<Future<Runnable>>();
for (int n = 0; n < 1000; n++)
{
Future f = service.submit(new DoSomethingInAThread());
futures.add(f);
}
// wait for all tasks to complete before continuing
for (Future<Runnable> f : futures)
{
f.get();
}
//shut down the executor service so that this thread can exit
service.shutdownNow();
}
public void run()
{
// do something here
}
}
join()
오래된 API인 Count Down Latch를 사용할 수 있습니다.저는 당신의 요구를 충족시키기 위해 당신의 코드를 아래와 같이 수정했습니다.
import java.util.concurrent.*;
class DoSomethingInAThread implements Runnable{
CountDownLatch latch;
public DoSomethingInAThread(CountDownLatch latch){
this.latch = latch;
}
public void run() {
try{
System.out.println("Do some thing");
latch.countDown();
}catch(Exception err){
err.printStackTrace();
}
}
}
public class CountDownLatchDemo {
public static void main(String[] args) {
try{
CountDownLatch latch = new CountDownLatch(1000);
for (int n=0; n<1000; n++) {
Thread t = new Thread(new DoSomethingInAThread(latch));
t.start();
}
latch.await();
System.out.println("In Main thread after completion of 1000 threads");
}catch(Exception err){
err.printStackTrace();
}
}
}
설명:
CountDownLatch
고객님의 요건에 따라 지정된 카운트 1000으로 초기화되었습니다.스레드 " " " "
DoSomethingInAThread
를 누르면 됩니다.CountDownLatch
이치노스레드 인인 main main main
CountDownLatchDemo
await()
출력은 .카운트가 0이 되면 출력은 라인 아래로 내려갑니다.In Main thread after completion of 1000 threads
Oracle 문서 페이지에서 자세한 정보 보기
public void await()
throws InterruptedException
스레드가 중단되지 않는 한 래치가 0까지 카운트다운될 때까지 현재 스레드가 대기합니다.
기타 옵션에 대해서는 관련 SE 질문을 참조하십시오.
모든 스레드의 작업이 Java로 완료될 때까지 기다리다
스레드 클래스는 완전히 피하고 대신 java.util.concurrent에서 제공하는 상위 추상화를 사용합니다.
ExecutorService 클래스는 원하는 대로 수행할 수 있는 invokeAll 메서드를 제공합니다.
을 검토해 주세요.java.util.concurrent.CountDownLatch
. javadocs의 예
K가 제안한 'KK'는java.util.concurrent.CountDownLatch
더 나은 해결책이 될 것 같습니다., 같은 로 들겠습니다.
public class CountDownLatchDemo
{
public static void main (String[] args)
{
int noOfThreads = 5;
// Declare the count down latch based on the number of threads you need
// to wait on
final CountDownLatch executionCompleted = new CountDownLatch(noOfThreads);
for (int i = 0; i < noOfThreads; i++)
{
new Thread()
{
@Override
public void run ()
{
System.out.println("I am executed by :" + Thread.currentThread().getName());
try
{
// Dummy sleep
Thread.sleep(3000);
// One thread has completed its job
executionCompleted.countDown();
}
catch (InterruptedException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}.start();
}
try
{
// Wait till the count down latch opens.In the given case till five
// times countDown method is invoked
executionCompleted.await();
System.out.println("All over");
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
}
필요에 따라서는 java.util.concurrent 패키지의 CountDownLatch 및 CyclicBarrier 클래스를 체크할 수도 있습니다.스레드가 서로 대기하도록 하거나 스레드 실행 방법을 보다 세밀하게 제어하려는 경우(예를 들어 내부 실행에서 다른 스레드가 어떤 상태를 설정하기를 기다리는 경우)에 유용합니다.또한 CountDownLatch를 사용하여 루프를 반복할 때 스레드를 하나씩 시작하지 않고 모든 스레드를 동시에 시작하도록 신호를 보낼 수도 있습니다.표준 API 문서에는 이와 같은 예가 있으며 다른 CountDownLatch를 사용하여 모든 스레드의 실행을 기다립니다.
스레드 목록을 작성하면 스레드 및 .join()을 각각에 대해 루프할 수 있습니다.이러한 루프는 모든 스레드가 완료되면 종료됩니다.안 먹어봤는데.
http://docs.oracle.com/javase/8/docs/api/java/lang/Thread.html#join()
첫 번째 for 루프 내에 스레드개체를 만듭니다.
for (int i = 0; i < threads.length; i++) {
threads[i] = new Thread(new Runnable() {
public void run() {
// some code to run in parallel
}
});
threads[i].start();
}
그리고 여기 있는 모든 사람들이 말하는 것입니다.
for(i = 0; i < threads.length; i++)
threads[i].join();
개체 "ThreadGroup"과 해당 매개 변수 activeCount를 사용하여 수행할 수 있습니다.
CountDownLatch 대신 CyclicBarrier를 사용할 수도 있습니다.
public class ThreadWaitEx {
static CyclicBarrier barrier = new CyclicBarrier(100, new Runnable(){
public void run(){
System.out.println("clean up job after all tasks are done.");
}
});
public static void main(String[] args) {
for (int i = 0; i < 100; i++) {
Thread t = new Thread(new MyCallable(barrier));
t.start();
}
}
}
class MyCallable implements Runnable{
private CyclicBarrier b = null;
public MyCallable(CyclicBarrier b){
this.b = b;
}
@Override
public void run(){
try {
//do something
System.out.println(Thread.currentThread().getName()+" is waiting for barrier after completing his job.");
b.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}
}
이 경우에 CyclicBarrier를 사용하려면 , 스레드가 작업을 완료했을 때의 마지막 스테이트먼트가 됩니다.CyclicBarrier는 reset() 메서드와 함께 다시 사용할 수 있습니다.javadocs를 인용하려면:
CyclicBarrier는 옵션인 Runnable 명령을 지원합니다.이 명령어는 장벽 포인트별로 1회 실행 후 파티 내 마지막 스레드가 도착한 후 스레드가 해제되기 전에 실행됩니다.이 장벽 액션은 당사자 중 하나가 계속하기 전에 공유 상태를 갱신할 때 유용합니다.
join()
도움이 되지 않았습니다.코틀린에서 다음 샘플을 참조하십시오.
val timeInMillis = System.currentTimeMillis()
ThreadUtils.startNewThread(Runnable {
for (i in 1..5) {
val t = Thread(Runnable {
Thread.sleep(50)
var a = i
kotlin.io.println(Thread.currentThread().name + "|" + "a=$a")
Thread.sleep(200)
for (j in 1..5) {
a *= j
Thread.sleep(100)
kotlin.io.println(Thread.currentThread().name + "|" + "$a*$j=$a")
}
kotlin.io.println(Thread.currentThread().name + "|TaskDurationInMillis = " + (System.currentTimeMillis() - timeInMillis))
})
t.start()
}
})
그 결과:
Thread-5|a=5
Thread-1|a=1
Thread-3|a=3
Thread-2|a=2
Thread-4|a=4
Thread-2|2*1=2
Thread-3|3*1=3
Thread-1|1*1=1
Thread-5|5*1=5
Thread-4|4*1=4
Thread-1|2*2=2
Thread-5|10*2=10
Thread-3|6*2=6
Thread-4|8*2=8
Thread-2|4*2=4
Thread-3|18*3=18
Thread-1|6*3=6
Thread-5|30*3=30
Thread-2|12*3=12
Thread-4|24*3=24
Thread-4|96*4=96
Thread-2|48*4=48
Thread-5|120*4=120
Thread-1|24*4=24
Thread-3|72*4=72
Thread-5|600*5=600
Thread-4|480*5=480
Thread-3|360*5=360
Thread-1|120*5=120
Thread-2|240*5=240
Thread-1|TaskDurationInMillis = 765
Thread-3|TaskDurationInMillis = 765
Thread-4|TaskDurationInMillis = 765
Thread-5|TaskDurationInMillis = 765
Thread-2|TaskDurationInMillis = 765
, 그럼 이번에는 '먹다'를 .join()
★★★★★★★★★★★★★★★★★★:
val timeInMillis = System.currentTimeMillis()
ThreadUtils.startNewThread(Runnable {
for (i in 1..5) {
val t = Thread(Runnable {
Thread.sleep(50)
var a = i
kotlin.io.println(Thread.currentThread().name + "|" + "a=$a")
Thread.sleep(200)
for (j in 1..5) {
a *= j
Thread.sleep(100)
kotlin.io.println(Thread.currentThread().name + "|" + "$a*$j=$a")
}
kotlin.io.println(Thread.currentThread().name + "|TaskDurationInMillis = " + (System.currentTimeMillis() - timeInMillis))
})
t.start()
t.join()
}
})
그 결과:
Thread-1|a=1
Thread-1|1*1=1
Thread-1|2*2=2
Thread-1|6*3=6
Thread-1|24*4=24
Thread-1|120*5=120
Thread-1|TaskDurationInMillis = 815
Thread-2|a=2
Thread-2|2*1=2
Thread-2|4*2=4
Thread-2|12*3=12
Thread-2|48*4=48
Thread-2|240*5=240
Thread-2|TaskDurationInMillis = 1568
Thread-3|a=3
Thread-3|3*1=3
Thread-3|6*2=6
Thread-3|18*3=18
Thread-3|72*4=72
Thread-3|360*5=360
Thread-3|TaskDurationInMillis = 2323
Thread-4|a=4
Thread-4|4*1=4
Thread-4|8*2=8
Thread-4|24*3=24
Thread-4|96*4=96
Thread-4|480*5=480
Thread-4|TaskDurationInMillis = 3078
Thread-5|a=5
Thread-5|5*1=5
Thread-5|10*2=10
Thread-5|30*3=30
Thread-5|120*4=120
Thread-5|600*5=600
Thread-5|TaskDurationInMillis = 3833
알 수 요.join
:
- 스레드가 순차적으로 실행됩니다.
- 첫 번째 샘플은 765밀리초, 두 번째 샘플은 3833밀리초가 걸립니다.
다른 스레드를 차단하지 않기 위한 솔루션은 Array List를 작성하는 것이었습니다.
val threads = ArrayList<Thread>()
새로운 스레드를 시작할 때는 대부분 Array List에 추가합니다.
addThreadToArray(
ThreadUtils.startNewThread(Runnable {
...
})
)
그addThreadToArray
기능:
@Synchronized
fun addThreadToArray(th: Thread) {
threads.add(th)
}
그startNewThread
기능:
fun startNewThread(runnable: Runnable) : Thread {
val th = Thread(runnable)
th.isDaemon = false
th.priority = Thread.MAX_PRIORITY
th.start()
return th
}
필요에 따라서, 다음의 순서로 스레드의 완료를 확인합니다.
val notAliveThreads = ArrayList<Thread>()
for (t in threads)
if (!t.isAlive)
notAliveThreads.add(t)
threads.removeAll(notAliveThreads)
if (threads.size == 0){
// The size is 0 -> there is no alive threads.
}
문제:
for(i = 0; i < threads.length; i++)
threads[i].join();
...그것은threads[i + 1]
이전에는 가입할 수 없다threads[i]
. "래치"를 제외한 모든 솔루션에는 이러한 기능이 없습니다.
여기서는 아직 Executor Completion Service에 대해 언급하지 않았습니다.완료 순서에 따라 스레드/태스크에 참여할 수 있습니다.
public class ExecutorCompletionService<V>
extends Object
implements CompletionService<V>
A
CompletionService
공급된 것을 사용한다.Executor
작업을 실행합니다.이 클래스는 제출된 작업을 완료 시 take를 사용하여 액세스할 수 있는 대기열에 배치합니다.이 클래스는 작업 그룹을 처리할 때 일시적으로 사용하기에 적합할 정도로 가볍습니다.사용 예
특정 문제에 대한 해결사 집합이 있으며 각각이 특정 유형의 값을 반환하고 Null이 아닌 값을 반환하는 각 해결사의 결과를 어떤 방법으로 처리하면서 동시에 실행하려고 합니다.
use(Result r)
. 다음과 같이 쓸 수 있습니다.void solve(Executor e, Collection<Callable<Result>> solvers) throws InterruptedException, ExecutionException { CompletionService<Result> cs = new ExecutorCompletionService<>(e); solvers.forEach(cs::submit); for (int i = solvers.size(); i > 0; i--) { Result r = cs.take().get(); if (r != null) use(r); } }
대신 작업 집합의 첫 번째 null이 아닌 결과를 사용하여 발생한 예외를 모두 무시하고 첫 번째 작업이 준비되었을 때 다른 모든 작업을 취소한다고 가정합니다.
void solve(Executor e, Collection<Callable<Result>> solvers) throws InterruptedException { CompletionService<Result> cs = new ExecutorCompletionService<>(e); int n = solvers.size(); List<Future<Result>> futures = new ArrayList<>(n); Result result = null; try { solvers.forEach(solver -> futures.add(cs.submit(solver))); for (int i = n; i > 0; i--) { try { Result r = cs.take().get(); if (r != null) { result = r; break; } } catch (ExecutionException ignore) {} } } finally { futures.forEach(future -> future.cancel(true)); } if (result != null) use(result); }
이후: 1.5 (!)
가정하다use(r)
(예 1의) 또한 비동기적이므로 큰 이점이 있었습니다.#
언급URL : https://stackoverflow.com/questions/1252190/how-to-wait-for-a-number-of-threads-to-complete
'programing' 카테고리의 다른 글
Larabel 뷰 내에 등록된 모든 변수 나열 (0) | 2023.01.10 |
---|---|
mysql에서 셀 데이터 변경 (0) | 2023.01.10 |
외부 볼륨을 연결하는 동안 도커 구성과 문제를 사용하여 mariadb 10.4.8 도커 컨테이너를 사용하는 사용자 'root'@'localhost'에 대한 액세스가 거부되었습니다. (0) | 2023.01.10 |
Pivotal Cloud Foundry는 MariaDB를 지원합니까? (0) | 2023.01.10 |
기능 프로그래밍 - 불변성은 비용이 많이 드나요? (0) | 2023.01.10 |