I have wrote following code:
System.out.println("Main thread:" + Thread.currentThread().getId());
CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
try {
System.out.println("Before sleep thread:" + Thread.currentThread().getId(), + " isDaemon:" + Thread.currentThread().isDaemon());
Thread.sleep(100);
System.out.println("After sleep");
} catch (InterruptedException e) {
e.printStackTrace();
}
});
future.whenComplete((r, e) -> System.out.println("whenCompleted thread:" + Thread.currentThread().getId()));
and this one prints:
Main thread:1
Before sleep thread:11 isDaemon:true
and finishes.
How can I change this behaviour?
P.S. I don't see anything related in runAsync java doc
The javadoc for runAsync() says:
Returns a new CompletableFuture that is asynchronously completed by a task running in the ForkJoinPool.commonPool() after it runs the given action.
There is another version of runAsync() where you can pass an ExecutorService.
Thus: when the default commonPool() doesn't do what you want - then create your own ExecutorService instead.
Add this line:
ForkJoinPool.commonPool().awaitTermination(5, TimeUnit.SECONDS);
to the main method after running your future. I'll block until all tasks in the pool have been completed.
Blocks until all tasks have completed execution after a shutdown request, or the timeout occurs, or the current thread is interrupted, whichever happens first.
Related
I'm learning Reactive programming with project-reactor.
I have the following test case:
#Test
public void createAFlux_just() {
Flux<String> fruitFlux = Flux.just("apple", "orange");
fruitFlux.subscribe(f -> {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(f);
});
System.out.println("hello main thread");
}
By executing the test it seems that the main thread is stuck for 5 seconds.
I would expect that the subscribed consumer should run asynchronously in its own thread, that is, the subscribe invoke should return immediately to the main thread and consequently the hello main thread should print instantly.
The main thread is stuck because the subscription happens on the main thread. If you want it to run asynchronously, you need to the subscription to happen on a thread other than main. You could do this as:
#Test
public void createAFlux_just() {
Flux<String> fruitFlux = Flux.just("apple", "orange");
fruitFlux.subscribeOn(Schedulers.parallel()).subscribe(f -> {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(f);
});
System.out.println("hello main thread");
}
Note: I have used the parallel thread pool. You could use whatever pool you like. Reactor's pipelines are executed on the calling thread by default (unlike CompletableFuture<T> which runs in the ForkJoin pool by default).
This behavior would be the case if you had an observable (Flux) that was asynchronous. You chose to use a Flux with two readily available values by using the just method. They were passed to the subscription object right away since they were immediately available.
from spring.io documentation
The Threading Model
Reactor operators generally are concurrent agnostic: they don’t impose a particular threading model and just run on the Thread on which their onNext method was invoked.
The Scheduler abstraction
In Reactor, a Scheduler is an abstraction that gives the user control about threading. A Scheduler can spawn Worker which are conceptually Threads, but are not necessarily backed by a Thread (we’ll see an example of that later). A Scheduler also includes the notion of a clock, whereas the Worker is purely about scheduling tasks.
so you should subscribe on different thread by subscribeOn method and the Thread.sleep(5000) will sleep thread of the scheduler. You can see more examples like this one in the documentation.
Flux.just("hello")
.doOnNext(v -> System.out.println("just " + Thread.currentThread().getName()))
.publishOn(Scheduler.boundedElastic())
.doOnNext(v -> System.out.println("publish " + Thread.currentThread().getName()))
.delayElements(Duration.ofMillis(500))
.subscribeOn(Schedulers.elastic())
.subscribe(v -> System.out.println(v + " delayed " + Thread.currentThread().getName()));
I want to use the Executor interface (using Callable) in order to start a Thread (let's call it callable Thread) which will do work that uses blocking methods.
That means the callable Thread can throw an InterruptedException when the main Thread calls the Future.cancel(true) (which calls a Thread.interrupt()).
I also want my callable Thread to properly terminate when interrupted USING other blocking methods in a cancellation part of code.
While implementing this, I experienced the following behavior: When I call Future.cancel(true) method, the callable Thread is correctly notified of the interruption BUT if the main Thread immediately waits for its termination using Future.get(), the callable Thread is kind of killed when calling any blocking method.
The following JUnit 5 snippet illustrates the problem.
We can easily reproduce it if the main Thread does not sleep between the cancel() and the get() calls.
If we sleep a while but not enough, we can see the callable Thread doing half of its cancellation work.
If we sleep enough, the callable Thread properly completes its cancellation work.
Note 1: I checked the interrupted status of the callable Thread: it is correctly set once and only once, as expected.
Note 2: When debugging step by step my callable Thread after interruption (when passing into the cancellation code), I "loose" it after several step when entering a blocking method (no InterruptedException seems to be thrown).
#Test
public void testCallable() {
ExecutorService executorService = Executors.newSingleThreadExecutor();
System.out.println("Main thread: Submitting callable...");
final Future<Void> future = executorService.submit(() -> {
boolean interrupted = Thread.interrupted();
while (!interrupted) {
System.out.println("Callable thread: working...");
try {
Thread.sleep(500);
} catch (InterruptedException e) {
System.out.println("Callable thread: Interrupted while sleeping, starting cancellation...");
Thread.currentThread().interrupt();
}
interrupted = Thread.interrupted();
}
final int steps = 5;
for (int i=0; i<steps; ++i) {
System.out.println(String.format("Callable thread: Cancelling (step %d/%d)...", i+1, steps));
try {
Thread.sleep(200);
} catch (InterruptedException e) {
Assertions.fail("Callable thread: Should not be interrupted!");
}
}
return null;
});
final int mainThreadSleepBeforeCancelMs = 2000;
System.out.println(String.format("Main thread: Callable submitted, sleeping %d ms...", mainThreadSleepBeforeCancelMs));
try {
Thread.sleep(mainThreadSleepBeforeCancelMs);
} catch (InterruptedException e) {
Assertions.fail("Main thread: interrupted while sleeping.");
}
System.out.println("Main thread: Cancelling callable...");
future.cancel(true);
System.out.println("Main thread: Cancelable just cancelled.");
// Waiting "manually" helps to test error cases:
// - Setting to 0 (no wait) will prevent the callable thread to correctly terminate;
// - Setting to 500 will prevent the callable thread to correctly terminate (but some cancel process is done);
// - Setting to 1500 will let the callable thread to correctly terminate.
final int mainThreadSleepBeforeGetMs = 0;
try {
Thread.sleep(mainThreadSleepBeforeGetMs);
} catch (InterruptedException e) {
Assertions.fail("Main thread: interrupted while sleeping.");
}
System.out.println("Main thread: calling future.get()...");
try {
future.get();
} catch (InterruptedException e) {
System.out.println("Main thread: Future.get() interrupted: Error.");
} catch (ExecutionException e) {
System.out.println("Main thread: Future.get() threw an ExecutionException: Error.");
} catch (CancellationException e) {
System.out.println("Main thread: Future.get() threw an CancellationException: OK.");
}
executorService.shutdown();
}
When you call get() on a canceled Future, you will get a CancellationException, hence will not wait for the Callable’s code to perform its cleanup. Then, you are just returning and the observed behavior of threads being killed seems to be part of JUnit’s cleanup when it has determined that the test has completed.
In order to wait for the full cleanup, change the last line from
executorService.shutdown();
to
executorService.shutdown();
executorService.awaitTermination(1, TimeUnit.DAYS);
Note that it is simpler to declare unexpected exceptions in the method’s throws clause rather than cluttering your test code with catch clauses calling Assertions.fail. JUnit will report such exceptions as failure anyway.
Then, you can remove the entire sleep code.
It might be worth putting the ExecutorService management into #Before/#After or even #BeforeClass/#AfterClass methods, to keep the testing methods free of that, to focus on the actual tests.¹
¹ These were the JUnit 4 names. IIRC, the JUnit 5 names are like #BeforeEach/#AfterEach resp. #BeforeAll/#AfterAll
I have written up a contrived code example, and it might not be code that someone ought to use, but I believe it should work. However it instead deadlocks. I've read the answers described here, but found them insufficient.
Here is the code example:
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
public class Test {
public static void main(String argv[]) throws Exception {
int nThreads = 1;
Executor executor = Executors.newFixedThreadPool( nThreads );
CompletableFuture.completedFuture(true)
.thenComposeAsync((unused)->{
System.err.println("About to enqueue task");
CompletableFuture<Boolean> innerFuture = new CompletableFuture<>();
executor.execute(() -> {
// pretend this is some really expensive computation done asynchronously
System.err.println("Inner task");
innerFuture.complete(true);
});
System.err.println("Task enqueued");
return innerFuture;
}, executor).get();
System.err.println("All done");
System.exit(0);
}
}
This prints:
About to enqueue task
Task enqueued
And then it hangs. It's deadlocked because the executor only has a single thread, and it's waiting for the innerFuture to become redeemable. Why does "thenComposeAsync" block for its return value to become redeemable, instead of returning the still-incomplete future and freeing up its thread in the executor?
This feels completely unintuitive, and the javadocs don't really help. Am I fundamentally misunderstanding how CompletionStages work? Or is this a bug in the implementation?
So, after a lot of interesting conversation, I decided to email one of the JDK authors. Found out that this behavior wasn't intended, and is indeed a bug present in 1.8u25. There is a fix that will be released with a later patch version of Java 8. I don't know which. For anyone wanting to test the new behavior, you can download the latest jsr166 jar here:
http://gee.cs.oswego.edu/dl/concurrency-interest/index.html
First, let me rewrite your code with 2 static functions to make it easier to see what's going on:
// Make an executor equivalent to Executors.newFixedThreadPool(nThreads)
// that will trace to standard error when a task begins or ends
static ExecutorService loggingExecutor(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<>()) {
#Override
protected void beforeExecute(Thread t, Runnable r) {
System.err.println("Executor beginning task on thread: "
+ t.getName());
}
#Override
protected void afterExecute(Runnable r, Throwable t) {
System.err.println("Executor finishing task on thread: "
+ Thread.currentThread().getName());
}
};
}
And
// same as what you pass to thenComposeAsync
static Function<Boolean, CompletableFuture<Boolean>> inner(Executor executor) {
return b -> {
System.err.println(Thread.currentThread().getName()
+ ": About to enqueue task");
CompletableFuture<Boolean> innerFuture = new CompletableFuture<>();
executor.execute(() -> {
System.err.println(Thread.currentThread().getName()
+ ": Inner task");
innerFuture.complete(true);
});
System.err.println(Thread.currentThread().getName()
+ ": Task enqueued");
return innerFuture;
};
}
Now we can write your test case as follows:
ExecutorService e = loggingExecutor(1);
CompletableFuture.completedFuture(true)
.thenComposeAsync(inner(e), e)
.join();
e.shutdown();
/* Output before deadlock:
Executor beginning task on thread: pool-1-thread-1
pool-1-thread-1: About to enqueue task
pool-1-thread-1: Task enqueued
*/
Let's test your conclusion that the first thread is not released until the result of the second future is computed:
ExecutorService e = loggingExecutor(2); // use 2 threads this time
CompletableFuture.completedFuture(true)
.thenComposeAsync(inner(e), e)
.join();
e.shutdown();
/*
Executor beginning task on thread: pool-1-thread-1
pool-1-thread-1: About to enqueue task
pool-1-thread-1: Task enqueued
Executor beginning task on thread: pool-1-thread-2
pool-1-thread-2: Inner task
Executor finishing task on thread: pool-1-thread-2
Executor finishing task on thread: pool-1-thread-1
*/
Indeed, it appears that thread 1 is held until thread 2 is done
Let's see if you are right that thenComposeAsync itself blocks:
ExecutorService e = loggingExecutor(1);
CompletableFuture<Boolean> future =
CompletableFuture.completedFuture(true)
.thenComposeAsync(inner(e), e);
System.err.println("thenComposeAsync returned");
future.join();
e.shutdown();
/*
thenComposeAsync returned
Executor beginning task on thread: pool-1-thread-1
pool-1-thread-1: About to enqueue task
pool-1-thread-1: Task enqueued
*/
thenComposeAsync didn't block. It returned the CompletableFuture right away and the deadlock only occurred when we tried to complete it. So what should it take to complete the future returned by .thenComposeAsync(inner(e), e)?
The API needs to wait for innner(e) to return CompletableFuture<Boolean>
it needs to wait for the returned CompletableFuture<Boolean> to also complete. Only then is the future complete. So, as you can see, it cannot do what you suggest and return the incomplete Future.
Is it a bug? Why does the CompletionStage hold on to thread 1 while the inner task is being computed? It is not a bug becuase, as you noted, the documentation is pretty vague and doesn't promise to release threads in any particular order. Also, note that Thread1 will be used for any subsequent then*() methods of CompletableFuture. Consider the following:
ExecutorService e = loggingExecutor(2);
CompletableFuture.completedFuture(true)
.thenComposeAsync(inner(e), e)
.thenRun(() -> System.err.println(Thread.currentThread().getName()
+ ": All done"))
.join();
e.shutdown();
/*
Executor beginning task on thread: pool-1-thread-1
pool-1-thread-1: About to enqueue task
pool-1-thread-1: Task enqueued
Executor beginning task on thread: pool-1-thread-2
pool-1-thread-2: Inner task
Executor finishing task on thread: pool-1-thread-2
pool-1-thread-1: All done
Executor finishing task on thread: pool-1-thread-1
*/
As you can see, .thenRun(...) got executed on thread 1. I believe this is consistent with other *Async(... , Executor exec) methods of CompletableFuture.
But what if you want to split up the functionality of thenComposeAsync into 2 separately controllable steps instead of leaving it up to the API to juggle threads? You can just do this:
ExecutorService e = loggingExecutor(1);
completedFuture(true)
.thenApplyAsync(inner(e), e) // do the async part first
.thenCompose(x -> x) // compose separately
.thenRun(() -> System.err.println(Thread.currentThread().getName()
+ ": All done"))
.join();
e.shutdown();
Everything will run nicely on 1 thread with no deadlocks.
In conclusion, is this behavior of unintuitive as you say? I don't know. I cannot imagine why thenComposeAsync even exists. If a method returns CompletableFuture, it shouldn't block and there should be no reason to call it asynchronously.
InWhen invokeAny successfully returns, what happens to remaining threads? Does it get killed automatically? If not how can I make sure that thread is stopped and return back to threadpool
ExecutorService executorService = Executors.newFixedThreadPool(10);
executorService.invokeAny(callables);
Just elaborating more on the topic.
What happens to remaining threads
If the treads are executing methods which throw InterruptedException then they receive the exception. Otherwise they get their interrupted flag set to true.
Does it get killed automaticlly?
Not really.- If they are running in infinite loop then you need to make sure you do not swallow InterruptedException and exit the thread in the catch block.- If you are not expecting the exception then you need to keep checking flag using Thread.interrupted() or Thread.currentThread().isInterrupted() and exit when it's true.
- If you are not running infinite loop then the threads will complete their tasks and stop. But their results will not be considered.
In following code both task, and task2 keep running even the service is stopped and main method exits:
public class Test {
public static void main(String[] args) throws Exception {
Callable<String> task1 = () -> {
for (;;) {
try {
Thread.sleep(9000);
System.out.println(Thread.currentThread().getName()+
" is still running..");
} catch (InterruptedException e) {
System.out.println(Thread.currentThread().getName()
+ " has swallowed the exception.");
//it is a good practice to break the loop here or return
}
}
};
Callable<String> task2 = () -> {
for(;;) {
if(Thread.interrupted()) {
//it is a good practice to break the loop here or return
System.out.println(Thread.currentThread().getName()+
" is interrupted but it is still running..");
}
}
};
List<Callable<String>> tasks = List.of(task1, task2, () -> "small task done!");
ExecutorService service = Executors.newFixedThreadPool(4);
String result = service.invokeAny(tasks);
System.out.println(result);
service.shutdownNow();
System.out.println("main thread done");
}
}
Output:
small task done!
pool-1-thread-2 is interrupted but it is still running..
pool-1-thread-1 has swallowed the exception.
pool-1-thread-1 has swallowed the exception.
main thread done
pool-1-thread-1 is still running..
pool-1-thread-1 is still running..
Upon calling the method invokeAny they are all cancelled/stop when the remaining threads are not yet completed.
Here is the documentation of it:
Upon normal or exceptional return, tasks that have not completed are cancelled.
Is there a built-in way to cancel a Runnable task that has been scheduled at a fixed rate via ScheduledExecutorService.scheduleAtFixedRate and await it's completion if it happens to be running when cancel is called?.
Consider the following example:
public static void main(String[] args) throws InterruptedException, ExecutionException {
Runnable fiveSecondTask = new Runnable() {
#Override
public void run() {
System.out.println("5 second task started");
long finishTime = System.currentTimeMillis() + 5_000;
while (System.currentTimeMillis() < finishTime);
System.out.println("5 second task finished");
}
};
ScheduledExecutorService exec = Executors.newSingleThreadScheduledExecutor();
ScheduledFuture<?> fut = exec.scheduleAtFixedRate(fiveSecondTask, 0, 1, TimeUnit.SECONDS);
Thread.sleep(1_000);
System.out.print("Cancelling task..");
fut.cancel(true);
System.out.println("done");
System.out.println("isCancelled : " + fut.isCancelled());
System.out.println("isDone : " + fut.isDone());
try {
fut.get();
System.out.println("get : didn't throw exception");
}
catch (CancellationException e) {
System.out.println("get : threw exception");
}
}
The output of this program is:
5 second task started
Cancelling task..done
isCancelled : true
isDone : true
get : threw exception
5 second task finished
Setting a shared volatile flag seems the simplest option, but I'd prefer to avoid it if possible.
Does the java.util.concurrent framework have this capability built in?
I am not entirely sure what are you trying to achieve but as I went here from google search I thought It may be worth responding to your question.
1) If you want to forcibly stop heavy workload - unfortunately it seems there is no solution for it(when thread does not respond to interrupts). Only way of dealing with it would be to insert Thread.sleep(1) in between time consuming operations in your loop (http://docs.oracle.com/javase/1.5.0/docs/guide/misc/threadPrimitiveDeprecation.html) - maybe deamon thread would help here but I really discourage using them.
2) If you want to block current thread until the child thread finishes then instead of calling cancel you can use get http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/Future.html#get() or even get with timeout.
3) If you want clean cancel of subthread then you can call:
fut.cancel(false);
this will not interrupt current execution but will not schedule it to run again.
4) If your workload is not heavy and you only need to wait for 5 seconds then use thread sleep or TimeUnit sleep. In such case interrupt / cancel will be immediate.
Also your example lacking shutdown call on Executor which cause application does not stop.