I've a list of Runnable
tasks (e.g. it contains 100 tasks, and each task takes randomly 1 - 10 seconds). The tasks must run in parallel and from the thread pool provided by ExecutorService
(e.g. my system has 4 CPUs, then it should run 4 tasks at the same time).
The question is: I wanted to know which tasks took longer than 5 seconds to run from the list of 100 tasks and they should be terminated (with logs of task ids) after 5 seconds to have places for other tasks.
I've looked at Future
with executorService.submit(Runnable task)
but the Future.get()
method will block the main thread and it is not what I wanted. Any suggestions would be great.
public class TestExecutorService {
private static final ExecutorService executorService = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() * 10);
public static void main(String[] args) throws InterruptedException {
List<Callable<Object>> tasks = new ArrayList<>();
for (int i = 0; i < 100; i++) {
int finalI = i;
int min = 1;
int max = 8;
Runnable runnable = new Runnable() {
@Override
public void run() {
try {
int sleepTime = min + (int)(Math.random() * ((max - min) + 1));
System.out.println("## Thread: " + finalI + " will sleep: " + sleepTime + " seconds.");
Thread.sleep(sleepTime * 1000);
System.out.println("## Thread: " + finalI + " finished after: " + sleepTime + " seconds");
} catch (InterruptedException e) {
System.out.println("Thread is cancelled!");
}
}
};
tasks.add(Executors.callable(runnable));
}
// How to make a Runnable task timeout after 5 seconds when running other tasks in parallel
// instead of total time for 100 tasks in 5 seconds?
executorService.invokeAll(tasks, 5, TimeUnit.SECONDS);
executorService.shutdown();
}
}
Lets say you have some list of tasks, and an Executor to
List<Runnable> tasks = ...;
ExecutorService executor = ...;
Now you want to perform each task, get the time it takes, and cancel the task if it takes too long. I would suggest scheduling a time out action.
ScheduledExecutorService timeoutService = Executors.newSingleThreadScheduledExecutor();
Now when you're submitting your tasks.
List<Future<Long>> results = new ArrayList<>();
for(int i = 0; i<tasks.size(); i++){
Runnable task = tasks.get(i);
Future<Long> future = executor.submit( () ->{
long start = System.currentTimeMillis();
task.run();
return System.currentTimeMillis() - start;
});
Future<?> timeout = timeoutService.schedule( ()->{
if(!future.isDone()){
future.cancel(true);
}
}, 5, TimeUnit.SECONDS);
results.add(future);
}
Now you can just go through results
and call get
when all of the tasks have finished, either exceptionally or normally, you will finish going through the results list. This assumes your tasks can be cancelled or interrupted If they cannot, then you can use the timeout futures.