我使用java.util.concurrent.ExecutorService和fixed thread pool来执行任务列表。我的任务列表通常大约为80-150,我将任何时候运行的线程数限制为10,如下所示:
ExecutorService threadPoolService = Executors.newFixedThreadPool(10);
for ( Runnable task : myTasks )
{
threadPoolService.submit(task);
}
我的用例要求即使已完成的任务也应该重新提交到 ExecutorService ,但只有在所有已经提交的任务时才应该执行/再次执行服务/完成。基本上,提交的任务应该以轮换方式执行。因此,在这种情况下,不会threadPoolService.shutdown()
或threadPoolService.shutdownNow()
调用。
我的问题是,如何实现 ExecutorService 服务轮换基础任务?
答案 0 :(得分:10)
ThreadPoolExecutor为afterExecution提供了一个扩展点,您可以将作业放回队列的末尾。
public class TaskRepeatingThreadPoolExecutor extends ThreadPoolExecutor {
public TaskRepeatingThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) {
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
}
@Override
protected void afterExecute(Runnable r, Throwable t) {
super.afterExecute(r, t);
this.submit(r);
}
}
当然,如果没有ExecutorService
方便的工厂方法的帮助,你必须做更多的工作来自己实例化它,但构造函数很简单,可以理解。
答案 1 :(得分:1)
答案与用于ExecutorService
实例的工作队列的实现更相关。所以,我建议:
首先选择java.util.concurrent.BlockingQueue
(an example)的实现,该实现提供循环队列功能。 注意,选择BlockingQueue
的原因是等待直到下一个任务提供给队列;所以,在循环+阻塞队列的情况下,你应该小心如何提供相同的行为和功能。
不使用Executors.new...
创建新的ThreadPoolExecutor
,而是使用direct constructor,例如
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue)
这样,除非您将执行程序命令到shutdown
,否则它将尝试从队列中获取下一个任务,以便从工作队列执行,这是一个循环< / em>任务容器。
答案 2 :(得分:1)
我建议以下解决方案完全使用标准库并发工具中存在的功能。它使用CyclicBarrier
和任务装饰器类以及重新提交所有任务的屏障操作:
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Rotation {
private static final class RotationDecorator implements Runnable {
private final Runnable task;
private final CyclicBarrier barrier;
RotationDecorator( Runnable task, CyclicBarrier barrier ) {
this.task = task;
this.barrier = barrier;
}
@Override
public void run() {
this.task.run();
try {
this.barrier.await();
} catch(InterruptedException e) {
; // Consider better exception handling
} catch(BrokenBarrierException e) {
; // Consider better exception handling
}
}
}
public void startRotation( List<Runnable> tasks ) {
final ExecutorService threadPoolService = Executors.newFixedThreadPool( 10 );
final List<Runnable> rotatingTasks = new ArrayList<Runnable>( tasks.size() );
final CyclicBarrier barrier = new CyclicBarrier( tasks.size(), new Runnable() {
@Override
public void run() {
Rotation.this.enqueueTasks( threadPoolService, rotatingTasks );
}
} );
for(Runnable task : tasks) {
rotatingTasks.add( new RotationDecorator( task, barrier ) );
}
this.enqueueTasks( threadPoolService, rotatingTasks );
}
private void enqueueTasks( ExecutorService service, List<Runnable> tasks ) {
for(Runnable task : tasks) {
service.submit( task );
}
}
}
答案 3 :(得分:1)
您可以简单地检查所有任务是否已执行,并在情况发生后重新提交,例如:
List<Future> futures = new ArrayList<>();
for (Runnable task : myTasks) {
futures.add(threadPoolService.submit(task));
}
//wait until completion of all tasks
for (Future f : futures) {
f.get();
}
//restart
......
修改强>
您似乎希望在任务完成后立即重新提交。您可以使用ExecutorCompletionService使您能够在执行任务时检索任务, - 请参阅下面的一个简单示例,其中包含2个任务,一旦完成就会重新提交几次。样本输出:
任务1提交了pool-1-thread-1
任务2提交了pool-1-thread-2
任务1完成了pool-1-thread-1
任务1提交了pool-1-thread-3
任务2完成了pool-1-thread-2
任务1完成了pool-1-thread-3
任务2提交了pool-1-thread-4
任务1提交了pool-1-thread-5
任务1完成了pool-1-thread-5
任务2完成了pool-1-thread-4
public class Test1 {
public final ConcurrentMap<String, String> concurrentMap = new ConcurrentHashMap<>();
public final AtomicInteger retries = new AtomicInteger();
public final Object lock = new Object();
public static void main(String[] args) throws InterruptedException, ExecutionException {
int count = 0;
List<Runnable> myTasks = new ArrayList<>();
myTasks.add(getRunnable(1));
myTasks.add(getRunnable(2));
ExecutorService threadPoolService = Executors.newFixedThreadPool(10);
CompletionService<Runnable> ecs = new ExecutorCompletionService<Runnable>(threadPoolService);
for (Runnable task : myTasks) {
ecs.submit(task, task);
}
//wait until completion of all tasks
while(count++ < 3) {
Runnable task = ecs.take().get();
ecs.submit(task, task);
}
threadPoolService.shutdown();
}
private static Runnable getRunnable(final int i) {
return new Runnable() {
@Override
public void run() {
System.out.println("Task " + i + " submitted " + Thread.currentThread().getName() + " ");
try {
Thread.sleep(500 * i);
} catch (InterruptedException ex) {
System.out.println("Interrupted");
}
System.out.println("Task " + i + " completed " + Thread.currentThread().getName() + " ");
}
};
}
}