web-dev-qa-db-ja.com

多数のスレッドが完了するのを待つ方法は?

すべてのスレッド化されたプロセスが終了するのを単に待つ方法は何ですか?たとえば、私が持っているとしましょう:

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()メソッドがコメントで一時停止するようにするにはどうすればよいですか?ありがとう!

101
DivideByHero

すべてのスレッドを配列に入れ、それらをすべて開始してから、ループを作成します

for(i = 0; i < threads.length; i++)
  threads[i].join();

各結合は、それぞれのスレッドが完了するまでブロックされます。スレッドは、参加する順序とは異なる順序で完了する場合がありますが、それは問題ではありません。ループが終了すると、すべてのスレッドが完了します。

157

1つの方法は、List of Threadsを作成し、各スレッドを作成して起動し、リストに追加することです。すべてが起動したら、リストをループバックし、それぞれに対してjoin()を呼び出します。スレッドが実行を終了する順序は関係ありません。知っておく必要があるのは、2番目のループの実行が完了するまでに、すべてのスレッドが完了することです。

より良いアプローチは、 ExecutorService とそれに関連するメソッドを使用することです:

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

ExecutorService(およびJava 5の 同時実行ユーティリティ からの新しいものすべて)の使用は非常に柔軟であり、上記の例は表面をほとんど傷つけません。

37
Adam Batkin
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
   }
}
24
jt.

Threadクラスを完全に避け、代わりにJava.util.concurrentで提供されるより高い抽象化を使用します

ExecutorServiceクラスは、 メソッドinvokeAll を提供します。

8
henrik

古いAPIであるjoin()の代わりに、 CountDownLatch を使用できます。要件を満たすために、コードを次のように変更しました。

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();
        }
    }
}

説明

  1. CountDownLatchは、要件に従って指定されたカウント1000で初期化されました。

  2. 各ワーカースレッドDoSomethingInAThreadは、コンストラクターで渡されたCountDownLatchをデクリメントします。

  3. メインスレッドCountDownLatchDemoawait()は、カウントがゼロになるまで。カウントがゼロになると、出力が次のようになります。

    In Main thread after completion of 1000 threads
    

Oracleドキュメントページからの詳細

public void await()
           throws InterruptedException

スレッドが中断されない限り、ラッチがゼロまでカウントダウンするまで現在のスレッドを待機させます。

他のオプションについては、関連するSEの質問を参照してください。

すべてのスレッドがJavaで作業を完了するまで待つ

8
Ravindra babu

Martin Kが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();
        }
    }

}
6
Freaky Thommi

Java.util.concurrent.CountDownLatchの使用を検討してください。 javadocs の例

4
Pablo Cavalieri

ニーズに応じて、Java.util.concurrentパッケージのCountDownLatchクラスとCyclicBarrierクラスをチェックアウトすることもできます。スレッドが相互に待機するようにしたい場合、またはスレッドの実行方法をよりきめ細かく制御したい場合(たとえば、別のスレッドが何らかの状態を設定するために内部実行で待機する場合)に役立ちます。また、CountDownLatchを使用して、ループを繰り返すときにスレッドを1つずつ開始する代わりに、すべてのスレッドに同時に開始するように通知することもできます。標準のAPIドキュメントには、この例に加えて、別のCountDownLatchを使用して、すべてのスレッドの実行が完了するまで待機します。

3
Jeff

スレッドのリストを作成すると、それらと各スレッドに対して.join()をループでき、すべてのスレッドが終了するとループが終了します。まだ試していません。

http://docs.Oracle.com/javase/8/docs/api/Java/lang/Thread.html#join()

3
David

これはコメントになりますが、まだコメントはできません。

MartinK、私はあなたがどのようにしたいのか興味がありますThreadGroupを使用します。前にそうしましたか?

上記のとおり、activeCountを確認することをお勧めします-脇に置いてMartinvLöwis現時点でのポーリングに関する懸念は、activeCount自体に別の懸念があります。

警告:私はこれを使ってみませんでしたので、私はこの問題の専門家ではありませんが、 javadocs によれば、estimateを返しますアクティブなスレッドの数。

個人的には、見積もりに基づいてシステムを構築しようとするのは嫌です。あなたはそれを行う方法について別の考えを持っていますか、またはjavadocを誤解していますか?

2
CPerkins

最初の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();
1
optimus0127

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を使用するには、barrier.await()が最後のステートメント、つまり、スレッドがジョブを完了したときでなければなりません。 CyclicBarrierは、reset()メソッドで再び使用できます。 javadocsを引用するには:

CyclicBarrierは、パーティの最後のスレッドが到着した後、スレッドがリリースされる前に、バリアポイントごとに1回実行されるオプションのRunnableコマンドをサポートします。このバリアアクションは、いずれかの当事者が続行する前に共有状態を更新するのに役立ちます。

0
shailendra1118

Object "ThreadGroup"およびそのパラメーターactiveCount を使用して実行できます。

0
Martin K.

join()は役に立たなかった。 Kotlinのこのサンプルを参照してください。

    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を使用すると明らかなように:

  1. スレッドは順番に実行されています。
  2. 最初のサンプルには765ミリ秒かかりますが、2番目のサンプルには3833ミリ秒かかります。

他のスレッドのブロックを防ぐためのソリューションは、ArrayListを作成することでした。

val threads = ArrayList<Thread>()

さて、新しいスレッドを開始したいときは、ほとんどArrayListに追加します。

addThreadToArray(
    ThreadUtils.startNewThread(Runnable {
        ...
    })
)

addThreadToArray関数:

@Synchronized
fun addThreadToArray(th: Thread) {
    threads.add(th)
}

startNewThread funstion:

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.
}
0
Misagh