簡體   English   中英

如何實現ExecutorService來執行批量任務

[英]How to implement an ExecutorService to execute batches of tasks

我正在尋找一種在java中執行批量任務的方法。 我們的想法是擁有一個基於線程池的ExecutorService ,它允許我在main線程的不同線程中傳播一組Callable 此類應提供waitForCompletion方法,該方法將main線程置於休眠狀態,直到執行所有任務。 然后應該喚醒main線程,它將執行一些操作並重新提交一組任務。

這個過程將重復多次,所以我想使用ExecutorService.shutdown因為這需要創建ExecutorService多個實例。

目前我已使用AtomicIntegerLock / Condition以下列方式實現它:

public class BatchThreadPoolExecutor extends ThreadPoolExecutor {
  private final AtomicInteger mActiveCount;
  private final Lock          mLock;
  private final Condition     mCondition;

  public <C extends Callable<V>, V> Map<C, Future<V>> submitBatch(Collection<C> batch){
    ...
    for(C task : batch){
      submit(task);
      mActiveCount.incrementAndGet();
    }
  }

  @Override
  protected void afterExecute(Runnable r, Throwable t) {
    super.afterExecute(r, t);
    mLock.lock();
    if (mActiveCount.decrementAndGet() == 0) {
      mCondition.signalAll();
    }
    mLock.unlock();
  }

  public void awaitBatchCompletion() throws InterruptedException {
    ...
    // Lock and wait until there is no active task
    mLock.lock();
    while (mActiveCount.get() > 0) {
      try {
        mCondition.await();
      } catch (InterruptedException e) {
        mLock.unlock();
        throw e;
      }
    }
    mLock.unlock();
  } 
}

請注意,我不一定會立即從批處理中提交所有任務,因此CountDownLatch似乎不是一個選項。

這是一種有效的方法嗎? 是否有更有效/更優雅的方式來實現它?

謝謝

我認為ExecutorService本身將能夠滿足您的要求。

調用invokeAll([...])並迭代所有任務。 如果您可以遍歷所有期貨,則所有任務都已完成。

正如其他答案所指出的那樣,您的用例似乎沒有任何需要自定義ExecutorService的部分。

在我看來,您需要做的就是提交批處理,等待它們全部完成而忽略主線程上的中斷,然后根據第一批的結果提交另一批。 我認為這只是一個問題:

    ExecutorService service = ...;

    Collection<Future> futures = new HashSet<Future>();
    for (Callable callable : tasks) {
        Future future = service.submit(callable);
        futures.add(future);
    }

    for(Future future : futures) {
        try {
            future.get();
        } catch (InterruptedException e) {
            // Figure out if the interruption means we should stop.
        }
    }

    // Use the results of futures to figure out a new batch of tasks.
    // Repeat the process with the same ExecutorService.

我同意@ckuetbach的默認Java Executors應該為您提供執行“批量”作業所需的所有功能。

如果我是你,我會提交一堆作業,等待他們用ExecutorService.awaitTermination() ,然后啟動一個新的ExecutorService 這樣做是為了節省“線程創建”是不成熟的優化,除非你每秒做100次這樣的事情。

如果你真的堅持為每個批次使用相同的ExecutorService ,那么你可以自己分配一個ThreadPoolExecutor ,並在循環中查看ThreadPoolExecutor.getActiveCount() 就像是:

BlockingQueue jobQueue = new LinkedBlockingQueue<Runnable>();
ThreadPoolExecutor executor = new ThreadPoolExecutor(NUM_THREADS, NUM_THREADS,
    0L, TimeUnit.MILLISECONDS, jobQueue);
// submit your batch of jobs ...
// need to wait a bit for the jobs to start
Thread.sleep(100);
while (executor.getActiveCount() > 0 && jobQueue.size() > 0) {
    // to slow the spin
    Thread.sleep(1000);
}
// continue on to submit the next batch

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM