[英]How to implement an ExecutorService to execute tasks on a rotation-basis?
[英]How to implement an ExecutorService to execute batches of tasks
我正在尋找一種在java中執行批量任務的方法。 我們的想法是擁有一個基於線程池的ExecutorService
,它允許我在main
線程的不同線程中傳播一組Callable
。 此類應提供waitForCompletion方法,該方法將main
線程置於休眠狀態,直到執行所有任務。 然后應該喚醒main
線程,它將執行一些操作並重新提交一組任務。
這個過程將重復多次,所以我想使用ExecutorService.shutdown
因為這需要創建ExecutorService
多個實例。
目前我已使用AtomicInteger
和Lock
/ 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.