Does service.schedule() method blocks other threads from running? - java

I have two newSingleThreadScheduledExecutor, scheduledService1 and scheduledService2.
ScheduledExecutorService scheduledService1 = Executors.newSingleThreadScheduledExecutor();
Runnable task1 = () -> System.out.println("Hello zoo1");
Callable<String> task2 = () -> "Monkey";
ScheduledFuture<?> result1 = scheduledService1.schedule(task1, 5, TimeUnit.SECONDS);
System.out.println(result1.get());
Future<?> result2 = scheduledService1.schedule(task2, 5, TimeUnit.SECONDS);
System.out.println(result2.get());
Runnable task3 = () -> System.out.println("Hello zoo2");
ScheduledExecutorService scheduledService2 = Executors.newSingleThreadScheduledExecutor();
scheduledService2.schedule(task3, 5, TimeUnit.SECONDS);
//blocked by scheduledService1?
ExecutorService es = Executors.newSingleThreadExecutor();
es.execute(() -> System.out.println("new single thread executor"));
System.out.println("main thread");
This outputs:
Hello zoo1
null
Monkey
main thread
new single thread executor
Hello zoo2
Based on the output, it seems that scheduledService1 blocks the main thread and es thread. Why is this so? Since "Hello zoo2" is printed last (from scheduledService2 task), why does it not block main and es thread as well. These are below the scheduledService2 declaration after all. Are my assumptions correct that only the first ScheduledExecutorService will block other threads and not the succeeding ScheduledExecutorService instance?

ScheduledFuture<?> result1 = scheduledService1.schedule(task1, 5, TimeUnit.SECONDS);
Neither scheduling task1, nor its execution will block the calling thread, as scheduledService1 uses its own background thread pool.
But, calling get on a Future will block the caller until the result is ready (i.e. the scheduled task has run to completion):
System.out.println(result1.get()); // this will block for 5 seconds

Related

shutdown only one task in ScheduledExecutorService

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-

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;
});

Will thread execution continues when waiting for Future of one thread

I want to know that when a program waits for Future object of one thread, will other threads continue their execution.
I have tried the below sample, it seems when my program is waiting for one thread, other threads are not continuing their execution. Please tell me whether this is correct or is there any issues with my code for handling threads.
ExecutorService executor = Executors.newFixedThreadPool(3);
for(int i=0; i<5 ;i++)
{
Worker w = new Worker();
Future<String> future = executor.submit(w);
while(!future.isDone())
{
//Wait
}
String s = future.get();
System.out.println(LocalDateTime.now()+" "+s);
}
executor.shutdown();
executor.awaitTermination(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
Below is my worker class:
public class Worker implements Callable<String> {
#Override
public String call() throws Exception {
// TODO Auto-generated method stub
Thread.sleep(3000);
return Thread.currentThread().getName();
}
}
I am getting the below results(Added date time to show that the results are not parallel):
2019-01-04T16:34:22.647 pool-1-thread-1
2019-01-04T16:34:25.661 pool-1-thread-2
2019-01-04T16:34:28.673 pool-1-thread-3
2019-01-04T16:34:31.685 pool-1-thread-1
2019-01-04T16:34:34.699 pool-1-thread-2
The problem
You presented the code which from main thread perspective waits (2) for each execution before submitting new task (1). In other words: in main thread you submit the task, wait for complete execution in main thread and submit next task after.
ExecutorService executor = Executors.newFixedThreadPool(3);
for(int i=0; i<5 ;i++)
{
Worker w = new Worker();
Future<String> future = executor.submit(w); // (1)
while(!future.isDone()) // (2)
{
//Wait
}
String s = future.get();
System.out.println(LocalDateTime.now()+" "+s);
}
executor.shutdown();
executor.awaitTermination(Long.MAX_VALUE, TimeUnit.MILLISECONDS);
Solution
To solve the issue you should (from main thread perspective) submit all tasks without waiting and then wait for results from executor service.
Example: https://stackoverflow.com/a/49746114/1815881
You can construct all tasks then call invokeAll() in ExecutorService.

If one thread throwing an exception then How to stop other waiting threads

In Java If I have three thread t1,t2 and t3. Suppose t1 is executing some task and t2,t3 are in a waiting state. Now If t1 is facing/throwing any kind of exception then I do not want to execute my t2,t3 thread.
How can we achive this functionality in Java?
Don't use threads directly, use the executor framework.
Specifically, use a CompletionService, so that you can retrieve the tasks you submit to the executor in order of completion (successful or otherwise).
Instead of:
Thread t1 = new Thread(() -> { /* runnable 1 */ });
Thread t2 = new Thread(() -> { /* runnable 2 */ });
Thread t3 = new Thread(() -> { /* runnable 3 */ });
Create a CompletionService:
ExecutorService executor = ...; // e.g. Executors.newFixedThreadPool
CompletionService completionService = new CompletionService(executor);
Now, create a list to hold the Futures returned by submitting tasks to the CompletionService:
List<Future<?>> futures = new ArrayList<>();
futures.add(completionService.submit(() -> { /* runnable 1 */ }));
futures.add(completionService.submit(() -> { /* runnable 2 */ }));
futures.add(completionService.submit(() -> { /* runnable 3 */ }));
Now, use take to get the futures in order of completion:
for (int i = 0; i < futures.size(); ++i) {
Future<?> completed = futures.take();
try {
completed.get();
} catch (ExecutionException e) {
// An exception occurred whilst running the task.
// Cancel all the tasks.
futures.forEach(f -> f.cancel(true));
}
}
Of course, for the cancel to do anything useful here, you would need your runnables to check for interruption; but you'd need to have some means of checking for "failure" in your other threads anyway.

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.

Categories

Resources