Java 执行器的正确使用方法是什么?

What is the right way to use Java executor?

我正在按以下方式使用 Java 执行器,但不确定是否每一行都是必需的,以及这是否是正确的使用方式:

  ExecutorService executor=Executors.newFixedThreadPool(30);
...
  int N=200;
  CountDownLatch doneSignal=new CountDownLatch(N);
  for (int i=0;i<N;i++) executor.execute(new Test_Runner(doneSignal,...));
  doneSignal.await();
  executor.shutdown();
  while (!executor.isTerminated()) { Thread.sleep(1000); }
  // Blocks until all tasks have completed execution after a shutdown request
  executor.awaitTermination(Long.MAX_VALUE, TimeUnit.DAYS);
...

class Test_Runner implements Runnable
{
  private CountDownLatch doneSignal;
  Thread Test_Runner_Thread;

  public Tes_Runner(CountDownLatch doneSignal,...)
  {
    this.doneSignal=doneSignal;
  }

// Define some methods

  public void run()
  {
    try
    {
//      do some work
    }
    catch (Exception e)
    {
      e.printStackTrace();
    }
    doneSignal.countDown();
  }

  public void start()
  {
    if (Test_Runner_Thread==null)
    {
      Test_Runner_Thread=new Thread(this);
      Test_Runner_Thread.setPriority(Thread.NORM_PRIORITY);
      Test_Runner_Thread.start();
    }
  }

  public void stop() { if (Test_Runner_Thread!=null) Test_Runner_Thread=null; }
}

在我看来是正确的。过去,我遵循 Java 7 JavaDoc 中关于 ExecutorService 的建议实现来停止它。您可以从 Java 7 Javadoc 获取它,但为了方便起见,我在下面提供了它。编辑它以满足您的需要,例如您可能想要传递等待的秒数。使用 CountDownLatch 的好处是,当它完成等待时,您知道 ExecutorService 将立即终止。此外,如果在未来的真实世界案例中需要,您可能希望为闩锁的等待添加超时。此外,在实际应用程序中使用时,将 latch.countDOwn() 放在 try 的 finally 块中。

 void shutdownAndAwaitTermination(ExecutorService pool) {
   pool.shutdown(); // Disable new tasks from being submitted
   try {
     // Wait a while for existing tasks to terminate
     if (!pool.awaitTermination(60, TimeUnit.SECONDS)) {
       pool.shutdownNow(); // Cancel currently executing tasks
       // Wait a while for tasks to respond to being cancelled
       if (!pool.awaitTermination(60, TimeUnit.SECONDS))
           System.err.println("Pool did not terminate");
     }
   } catch (InterruptedException ie) {
     // (Re-)Cancel if current thread also interrupted
     pool.shutdownNow();
     // Preserve interrupt status
     Thread.currentThread().interrupt();
   }
 }

您可以进一步简化代码。

  1. 您可以删除 CountDownLatch
  2. 将Test_Runner更改为Callable任务。
  3. 创建一个包含 Callable 个任务的 ArrayList。

      List<Test_Runner> callables = new ArrayList<Test_Runner>();
      for (int i=0;i<N;i++) {
         callables.add(new Test_Runner());
      }
    
  4. 在 executorService 上使用 invokeAll()

    List<Future<String>> futures = executorService.invokeAll(callables);
    

来自 javadocs,

<T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
                          throws InterruptedException

Executes the given tasks, returning a list of Futures holding their status and results when all complete. Future.isDone() is true for each element of the returned list. Note that a completed task could have terminated either normally or by throwing an exception. The results of this method are undefined if the given collection is modified while this operation is in progress.

并且您可以按照 Jose Martinez 的建议关闭 executorService

相关 SE 问题:How to shutdown an ExecutorService?