すべてのスレッド化されたプロセスが終了するのを単に待つ方法は何ですか?たとえば、私が持っているとしましょう:
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();
各結合は、それぞれのスレッドが完了するまでブロックされます。スレッドは、参加する順序とは異なる順序で完了する場合がありますが、それは問題ではありません。ループが終了すると、すべてのスレッドが完了します。
1つの方法は、List
of Thread
sを作成し、各スレッドを作成して起動し、リストに追加することです。すべてが起動したら、リストをループバックし、それぞれに対して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の 同時実行ユーティリティ からの新しいものすべて)の使用は非常に柔軟であり、上記の例は表面をほとんど傷つけません。
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
}
}
Threadクラスを完全に避け、代わりにJava.util.concurrentで提供されるより高い抽象化を使用します
ExecutorServiceクラスは、 メソッドinvokeAll を提供します。
古い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();
}
}
}
説明:
CountDownLatch
は、要件に従って指定されたカウント1000で初期化されました。
各ワーカースレッドDoSomethingInAThread
は、コンストラクターで渡されたCountDownLatch
をデクリメントします。
メインスレッドCountDownLatchDemo
await()
は、カウントがゼロになるまで。カウントがゼロになると、出力が次のようになります。
In Main thread after completion of 1000 threads
Oracleドキュメントページからの詳細
public void await()
throws InterruptedException
スレッドが中断されない限り、ラッチがゼロまでカウントダウンするまで現在のスレッドを待機させます。
他のオプションについては、関連するSEの質問を参照してください。
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();
}
}
}
Java.util.concurrent.CountDownLatch
の使用を検討してください。 javadocs の例
ニーズに応じて、Java.util.concurrentパッケージのCountDownLatchクラスとCyclicBarrierクラスをチェックアウトすることもできます。スレッドが相互に待機するようにしたい場合、またはスレッドの実行方法をよりきめ細かく制御したい場合(たとえば、別のスレッドが何らかの状態を設定するために内部実行で待機する場合)に役立ちます。また、CountDownLatchを使用して、ループを繰り返すときにスレッドを1つずつ開始する代わりに、すべてのスレッドに同時に開始するように通知することもできます。標準のAPIドキュメントには、この例に加えて、別のCountDownLatchを使用して、すべてのスレッドの実行が完了するまで待機します。
スレッドのリストを作成すると、それらと各スレッドに対して.join()をループでき、すべてのスレッドが終了するとループが終了します。まだ試していません。
http://docs.Oracle.com/javase/8/docs/api/Java/lang/Thread.html#join()
これはコメントになりますが、まだコメントはできません。
MartinK、私はあなたがどのようにしたいのか興味がありますThreadGroup
を使用します。前にそうしましたか?
上記のとおり、activeCount
を確認することをお勧めします-脇に置いてMartinvLöwis現時点でのポーリングに関する懸念は、activeCount
自体に別の懸念があります。
警告:私はこれを使ってみませんでしたので、私はこの問題の専門家ではありませんが、 javadocs によれば、estimateを返しますアクティブなスレッドの数。
個人的には、見積もりに基づいてシステムを構築しようとするのは嫌です。あなたはそれを行う方法について別の考えを持っていますか、またはjavadocを誤解していますか?
最初の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();
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コマンドをサポートします。このバリアアクションは、いずれかの当事者が続行する前に共有状態を更新するのに役立ちます。
Object "ThreadGroup"およびそのパラメーターactiveCount を使用して実行できます。
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
を使用すると明らかなように:
他のスレッドのブロックを防ぐためのソリューションは、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.
}