1

つまり、計算集約的なタスクを実行するオブジェクトがあります。

メイン クラスにこれらのオブジェクトが 2 つあると仮定して、次のようにプロセスを並列化しました。

Thread t1 = new Thread(new Runnable() {
            @Override
            public void run() {
                    obj1.compute();
            }
        });
Thread t2 = new Thread(new Runnable() {
            @Override
            public void run() {
                    obj2.compute();
            }
        });

        t1.start();
        t2.start();
        t1.join();
        t2.join();

しかし、任意の数のオブジェクトがリストに格納されている場合、それを行う最善の方法は何でしょうか? (数値は 10 の大きさであると仮定します)。エグゼキューター サービスを調べていましたが、スレッドに再参加する方法がわかりませんでした。ForkJoinPool はそれを行うことになっていますが、それを機能させる方法が見つかりませんでした。

私の優先事項は、パフォーマンスよりも単純で明確なコードです (計算にかかる 10 分でオーバーヘッドが見えなくなるため)。

4

3 に答える 3

4

返された先物を呼び出すだけgetで、タスクが完了するまでブロックされます。例えば:

ExecutorService executor = Executors.newFixedThreadPool(10);
List<Future> futures = new ArrayList<> ();

for (Runnable r : yourListOfRunnables) {
    futures.add(executor.submit(r));
}

//now do the equivalent of join:

try {
    for (Future f : futures) {
        f.get(); //blocks until the runnable completes
    }
} catch (...) { }

注: 完了したらエグゼキューターを忘れないでください。そうしないとshutdown、アプリケーションの終了が妨げられる可能性があります。

または、これが 1 回限りのものである場合はshutdown、executor を終了するまで待つことができます。

ExecutorService executor = Executors.newFixedThreadPool(10);

for (Runnable r : yourListOfRunnables) {
    executor.submit(r);
}

executor.shutdown(); //do not accept more tasks
executor.awaitTermination(Long.MAX_VALUE, SECONDS); //waits until all tasks complete

//at this point: all tasks have completed and 
//your executor is terminated: you can't reuse it
于 2013-03-06T19:08:26.713 に答える
1

java.util.concurrentを引き続き使用する別の方法:

import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class ForkJoin {
   static final int THREAD_COUNT = 10;
   public static void main( String[] args ) throws InterruptedException {
      ExecutorService executor = Executors.newFixedThreadPool( THREAD_COUNT );
      final CountDownLatch cdl = new CountDownLatch( THREAD_COUNT );
      for( int i = 0; i < THREAD_COUNT; ++i ) {
         executor.execute( new Runnable(){
            @Override public void run(){
               try {
                  Thread.sleep((long)( 2000.0 + 1000.0*Math.random()));
                  System.err.println( "Done." );
                  cdl.countDown();
               }
               catch( InterruptedException e ) {
                  e.printStackTrace();
               }
            }});
      }
      cdl.await( 1, TimeUnit.DAYS );
      executor.shutdownNow();
      System.err.println( "All done." );
   }
}

出力:

Done.
Done.
Done.
Done.
Done.
Done.
Done.
Done.
Done.
Done.
All done.
于 2013-03-06T19:49:11.860 に答える
0

このチュートリアルを見てみましょう: Executors と ThreadPoolExecutor を使用した Java スレッド プールの例、およびExecutorServiceのドキュメント。上記のように多数の実行可能なタスクを作成し、それらをリストに追加すると、それらすべてを一度にエグゼキューターにフィードし、それらすべてを 1 つのコレクションに戻すことができるはずです。

    tasks = new HashSet<Runnable>();
    for (int i = 0; i < 10; i++) {
        Runnable worker = new WorkerThread('' + i);
        tasks.add(worker);
      }

    //start processing and get a list of all the futures
    List<Future> futures = executor.invokeAll(tasks);
    for (Future f: futures) {
       f.get();
    }

リストの最初の Future は、最初に行われた Future ではないかもしれませんが、値を取得する際の遅延によって処理が遅くなりすぎないようにする必要があります。

于 2013-03-06T19:26:04.933 に答える