shutdown only one task in ScheduledExecutorService - java

I have a few tasks which are registered by
final ScheduledExecutorService ses = Executors.newScheduledThreadPool(10);
List<ScheduledFuture<?>> futures = new ArrayList<>();
tasks.forEach(task->{
var future = ses.scheduleWithFixedDelay(() -> run(task), 0, 3, TimeUnit.SECONDS);
futures.add(future);
});
// and now cancel all tasks one for one after 10 seconds..
ses.scheduleWithFixedDelay(() ->
{
log.info("cancel task----");
futures.get(0).cancel(false);
}, 0, 10, TimeUnit.SECONDS);
As you can see, for each task the futures holds a task.getId() so I can obtain the ScheduledFuture of a task afterwards. I do not want to ses.shutdown() because this will shutdown the whole schedulings for the other tasks as well, which I want to avoid.
The only solution I actually see is to create one ScheduledExecutorService for each task to be able to shutdown it afterwards for a specified task, but then I cannot make use of the pooling.
How can I shutdown only a specified task within the pool?

Use
Future<?> future;
future.cancel(false);
Cancel will cancel the task and any further scheduling of it.¹ The Boolean parameter decides if you want to throw an interruption exception on the task if it is already running and blocking on a resource.
To ensure the task is removed from the queue immediately upon cancelling, use the setRemoveOnCancelPolicy method on your ScheduledThreadPoolExecutor and set the policy to true.²
final ScheduledThreadPoolExecutor ses = (ScheduledThreadPoolExecutor) Executors.newScheduledThreadPool(10);
ses.setRemoveOnCancelPolicy(true);
¹ https://docs.oracle.com/javase/8/docs/api/index.html?java/util/concurrent/Future.html
² https://stackoverflow.com/a/36748183/4425643 , https://docs.oracle.com/javase/8/docs/api/java/util/concurrent/ScheduledThreadPoolExecutor.html#setRemoveOnCancelPolicy-boolean-

Related

How to set max execution time on individual tasks running on threads?

I have a set of tasks in multiple levels that I need to run in parallel on threads taken from a thread pool.
I am using a countdown latch to time the overall execution of the level.
Problem: there are few tasks which get to execute more than their individual time just because of other tasks present in the same level that have more execution time. I want to avoid that.
Below is the code I'm using.
private final ExecutorService executor = Executors.newCachedThreadPool(new ThreadFactoryBuilder().setNameFormat(
"TaskExecutor-thread-%d").build());
....
for (int i = 0; i < levels.size(); i++) {
Set<AbstractTask> taskSet = levels.get(i);
CountDownLatch latch = new CountDownLatch(taskSet.size());
int maxAwaitTime = TaskExecutorHelper.getMaxAwaitTime(taskSet); //this returns max of all
// execution time set for
//individual tasks
for (AbstractTask t : taskSet) {
executor.submit(() -> { t.doExecute(input); });
}
latch.await(maxAwaitTime, TimeUnit.MILLISECONDS);
}
Any help would be appreciated!
A possible solution is to set a task that will interrupt execution after given timeout. The following example may give you an idea:
private final ExecutorService executor = ...;
private final ScheduledExecutorService scheduler = ...;
Future future = executor.submit(() -> ... );
ScheduledFuture scheduledFuture = scheduler.schedule(() -> future.cancel(true), 10, TimeUnit.SECONDS);
You will need some code to cancel timeout handler after task execution.
See ScheduledExecutorService#schelude for details.

Is it possible to schedule a CompletableFuture?

Is there any way to schedule CompletableFuture in Java?
What I wanted to do is to schedule a task to be executed with some delay, and chain it with other operations to be performed asynchronously when it completes. So far I didn't find any way to do this.
For good ol' Futures we have e.g. ScheduledExecutorService, where we can schedule a task to be executed with some delay like this:
ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();
Future<String> future = scheduledExecutorService.schedule(() -> "someValue", 10, TimeUnit.SECONDS);
Is there any similar way for CompletableFutures?
If you're using Java 9+ then CompletableFuture#delayedExecutor(long,TimeUnit) may fit your needs:
Returns a new Executor that submits a task to the default executor after the given delay (or no delay if non-positive). Each delay commences upon invocation of the returned executor's execute method.
Executor delayed = CompletableFuture.delayedExecutor(10L, TimeUnit.SECONDS);
CompletableFuture.supplyAsync(() -> "someValue", delayed)
.thenAccept(System.out::println)
.join();
There's also an overload where you can specify the Executor to use in place of the "default executor".
As said, there is support in Java 9.
But it’s not hard to create a similar feature under Java 8; you already named the necessary elements:
// prefer this constructor with zero core threads for a shared pool,
// to avoid blocking JVM exit
static final ScheduledExecutorService SCHEDULER = new ScheduledThreadPoolExecutor(0);
static Executor delayedExecutor(long delay, TimeUnit unit)
{
return delayedExecutor(delay, unit, ForkJoinPool.commonPool());
}
static Executor delayedExecutor(long delay, TimeUnit unit, Executor executor)
{
return r -> SCHEDULER.schedule(() -> executor.execute(r), delay, unit);
}
which can be used similarly to the Java 9 feature:
Executor afterTenSecs = delayedExecutor(10L, TimeUnit.SECONDS);
CompletableFuture<String> future
= CompletableFuture.supplyAsync(() -> "someValue", afterTenSecs);
future.thenAccept(System.out::println).join();
Care must be taken to avoid that the shared scheduled executor’s threads prevent the JVM from terminating. The alternative to a zero core pool size is to use daemon threads:
static final ScheduledExecutorService SCHEDULER
= Executors.newSingleThreadScheduledExecutor(r -> {
Thread t = new Thread(r);
t.setDaemon(true);
return t;
});

what is the best way to know when all submitted tasks has been finished by Executor Service

here is two options , just bit confuse which one is best to go.
Option 1:
ExecutorService es = Executors.newFixedThreadPool(4);
List<Runnable> tasks = getTasks();
CompletableFuture<?>[] futures = tasks.stream()
.map(task -> CompletableFuture.runAsync(task, es))
.toArray(CompletableFuture[]::new);
CompletableFuture.allOf(futures).join();
es.shutdown();
Option 2:
ExecutorService es = Executors.newFixedThreadPool(4);
List< Future<?>> futures = new ArrayList<>();
for(Runnable task : taskList) {
futures.add(es.submit(task));
}
for(Future<?> future : futures) {
try {
future.get();
}catch(Exception e){
// do logging and nothing else
}
}
es.shutdown();
Here putting future.get(); in try catch is good idea right?
Since you effectively hold each submitted Future in a list of of futures by doing this:
List< Future<?>> futures = new ArrayList<>();
for(Runnable task : taskList) {
futures.add(es.submit(task));
}
You can very easily check if all the submitted jobs are done executing just, by invoking the Future#isDone method, which wilkl return true or false based on whether the task has finished or not. You can check more on this on the related documentation here.
Hence, with the above in mind you could very well create a simple helper method, that will iterate the list of your futures and check on their state. For example:
private boolean areJobsDone() {
return futures.stream()
.allMatch(Future::isDone);
}
Note that in contrast to the Future#get method, isDone is non blocking (as it's not waiting for the task to return it's result) as it effectively queries it's state.
With this you can go ahead and check for the state of your runnables, blocking the flow with a loop that will invoke the helper method, before proceeding.
Hope this helps.
There is another way to wait for all tasks to complete. After you submitted all of your tasks, call
es.shutdown()
es.awaitTermination(Long.MAX_VALUE, TimeUnit.NANO_SECONDS)
Oracle's Java Docs read:
shutdown [...] Initiates an orderly shutdown in which previously submitted tasks are executed.
awaitTermination [...] Blocks until all tasks have completed execution after a shutdown request, or the timeout occurs, or the current thread is interrupted, whichever happens first.
Concerning the timeout: with the above values, the thread-pool will only terminate after about 300 years.
Similar to the Aris_Kortex' proposal,
List<CompletableFuture<?>> futures = new ArrayList<>();
for(Runnable task : taskList) {
futures.add(CompletableFuture.runAsync(task, es));
}
and then create the combined CompletableFuture:
CompletableFuture<Void> cf = CompletableFuture.allOf(futures.toArray(futires.size()));
then you can wait for all tasks synchronously:
cf.get();
synchronously with timeout:
cf.get(1, TimeUnit.SECOND);
of asynchronously:
cf.thenRun(()->{finalActions();});

How to cancel ScheduledFuture task from another task and end gracefully?

I am playing with ScheduledExecutorService. What I want to do is to start a simple ticker (one tick per second) and schedule another task later (after five seconds) which cancels the first one. And then block the main thread until everything finishes, which should be after both tasks finish (+- five seconds).
This is my code:
ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
Runnable tickTask = () -> System.out.println("Tick");
ScheduledFuture<?> scheduledTickTask = executor.scheduleAtFixedRate(tickTask, 0, 1, TimeUnit.SECONDS);
Runnable cancelTask = () -> scheduledTickTask.cancel(true);
executor.schedule(cancelTask, 5, TimeUnit.SECONDS);
executor.awaitTermination(Long.MAX_VALUE, TimeUnit.DAYS);
The problem which suprises me is that it BLOCKS as if there were still some running tasks. Why? The cancelTask should end immediately and the scheduledTickTask was just cancelled, so what is the problem?
As per the Javadoc of ExecutorService.awaitTermination (emphasis mine):
Blocks until all tasks have completed execution after a shutdown request, or the timeout occurs, or the current thread is interrupted, whichever happens first.
That means you need to call shutdown first, like this:
ScheduledExecutorService executor = Executors.newSingleThreadScheduledExecutor();
Runnable tickTask = () -> System.out.println("Tick");
ScheduledFuture<?> scheduledTickTask = executor.scheduleAtFixedRate(tickTask, 0, 1, TimeUnit.SECONDS);
Runnable cancelTask = () -> {
scheduledTickTask.cancel(true);
executor.shutdown();
};
executor.schedule(cancelTask, 5, TimeUnit.SECONDS);
executor.awaitTermination(Long.MAX_VALUE, TimeUnit.DAYS);
In your case, the timeout will never happen because you practically set it to "infinity" and the current thread is not interrupted.

How to reuse ThreadPoolExecutor after shutdown

In my application i have used a custom ThreadPoolExecutor which enables pausing and resuming of the Executor by extending the ThreadPoolExecutor class. Same way I want to have Restart functionality implemented where after the shutdown method of the ExecutorService has been executed. I first tried with creating new instance of the ThreadPoolExecutor and it failed. I found this question and tried the ExecutorCompletionService which resulted the same failure where it didn't executed as intended.
First time when I click the start button in my UI it executes fine and after the completion of the process when I again start, it won't give me the intended result. Instead will give me the same previous result of the first run. What is the best suitable way which I can achieve this task ?
Thanks in advance :)
Following lines will be executed at each button click.
private static int jobs = 10;
ExecutorService executor = new PausableThreadPoolExecutor(num_threads, num_threads, 5000, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(jobs));
for (int i = 0; i < jobs; i++) {
Runnable worker = new TaskToDo(jobs);
executor.submit(worker);
}
executor.shutdown();
while (!executor.isTerminated()) {}
System.out.println("Finished all threads");
This is the source I used to have pause/resume implementation.
Maybe a ScheduledThreadPoolExecutor you can restart it ScheduledThreadPoolExecutor
using this the methods can return a ScheduledFuture ScheduledFuture or a Future Future to hold references to the tasks
ScheduledFuture now = null;
ScheduledThreadPoolExecutor scheduler = new ScheduledThreadPoolExecutor(1);
Runnable runner = new Runnable(){
public void run()
{
rollthedice(); //your method or runnable of choice
}
};
to start and restart something like "theres other methods too"
now = scheduler.scheduleAtFixedRate(runner, 0, 250, TimeUnit.MILLISECONDS);
to cancel or stop
now.cancel(true);
now = null;

Categories

Resources