1

所以问题是我有一个执行计算密集型任务的对象。

假设主类有两个这样的对象,我将过程并行化如下。

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执行程序,否则可能会阻止您的应用程序退出。

或者,如果这是一次性的事情,您可以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

看看这个教程:Java Thread Pool Example using Executors and ThreadPoolExecutor和ExecutorService上的文档。如果您像上面那样创建了许多可运行的任务,然后将它们添加到列表中,您应该能够一次将它们全部提供给您的执行程序,并将它们全部返回到一个集合中:

    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 回答