Just going through the CompletableFuture documentation and stumbled upon the completeExceptionally and obtrudeException methods and is having a hard time comprehending the difference and use case. Can the community help understand the difference and the use case with an example?
Explanation
The difference is subtle but important. From the official documentation:
completeExceptionally
If not already completed, causes invocations of get() and related methods to throw the given exception.
obtrudeException
Forcibly causes subsequent invocations of method get() and related methods to throw the given exception, whether or not already completed. [...]
So they differ in their behavior regarding CompletableFutures that are already completed.
Basically, a future can either be completed or still pending (not completed). When you call completeExceptionally or obtrudeException, the behavior differs depending on the state of the future at that point in time.
Already completed future
Consider this example where the future is already completed at the moment of calling the method:
CompletableFuture<String> future = CompletableFuture.completedFuture("hello world");
future.completeExceptionally(new RuntimeException("Oh noes!"));
System.out.println(future.get()); // Prints "hello world" just fine
versus
CompletableFuture<String> future = CompletableFuture.completedFuture("hello world");
future.obtrudeException(new RuntimeException("Oh noes!"));
System.out.println(future.get()); // Throws the exception
Not completed future
And in case the future is not completed yet, they will both throw an exception:
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
}
return "hello world";
});
future.completeExceptionally(new RuntimeException("Oh noes!"));
System.out.println(future.get());
and
CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
}
return "hello world";
});
future.obtrudeException(new RuntimeException("Oh noes!"));
System.out.println(future.get());
complete and obtrudeValue
Likewise there are also the methods complete and obtrudeValue which behave in the same way, but instead of throwing an exception, you can supply a value instead.
So complete basically completes the future with the given value, in case the future is not done yet, otherwise it does not do anything.
While obtrudeValue will supply the given value regardless, so it resets or cancels whatever the future already computed and replaces it by the given value instead.
completeExceptionally:
completableFuture.completeExceptionally(
new RuntimeException("Calculation failed!"));
//..
completableFuture.get(); //exception will be thrown whether `completableFuture` was not already completed.
obtrudeException:
completableFuture.obtrudeException(
new RuntimeException("Calculation failed!"));
//..
completableFuture.get(); //exception will be thrown **whether or not** `completableFuture` was completed.
Related
I am using Java 8, and I want to know the recommended way to enforce timeout on 3 async jobs that I would to execute async and retrieve the result from the future. Note that the timeout is the same for all 3 jobs. I also want to cancel the job if it goes beyond time limit.
I am thinking something like this:
// Submit jobs async
List<CompletableFuture<String>> futures = submitJobs(); // Uses CompletableFuture.supplyAsync
List<CompletableFuture<Void>> all = CompletableFuture.allOf(futures.toArray(new CompletableFuture[0]));
try {
allFutures.get(100L, TimeUnit.MILLISECONDS);
} catch (TimeoutException e){
for(CompletableFuture f : future) {
if(!f.isDone()) {
/*
From Java Doc:
#param mayInterruptIfRunning this value has no effect in this
* implementation because interrupts are not used to control
* processing.
*/
f.cancel(true);
}
}
}
List<String> output = new ArrayList<>();
for(CompeletableFuture fu : futures) {
if(!fu.isCancelled()) { // Is this needed?
output.add(fu.join());
}
}
return output;
Will something like this work? Is there a better way?
How to cancel the future properly? Java doc says, thread cannot be interrupted? So, if I were to cancel a future, and call join(), will I get the result immediately since the thread will not be interrupted?
Is it recommended to use join() or get() to get the result after waiting is over?
It is worth noting that calling cancel on CompletableFuture is effectively the same as calling completeExceptionally on the current stage. The cancellation will not impact prior stages. With that said:
In principle, something like this will work assuming upstream cancellation is not necessary (from a pseudocode perspective, the above has syntax errors).
CompletableFuture cancellation will not interrupt the current thread. Cancellation will cause all downstream stages to be triggered immediately with a CancellationException (will short circuit the execution flow).
'join' and 'get' are effectively the same in the case where the caller is willing to wait indefinitely. Join handles wrapping the checked Exceptions for you. If the caller wants to timeout, get will be needed.
Including a segment to illustrate the behavior on cancellation. Note how downstream processes will not be started, but upstream processes continue even after cancellation.
public static void main(String[] args) throws Exception
{
int maxSleepTime = 1000;
Random random = new Random();
AtomicInteger value = new AtomicInteger();
List<String> calculatedValues = new ArrayList<>();
Supplier<String> process = () -> { try { Thread.sleep(random.nextInt(maxSleepTime)); System.out.println("Stage 1 Running!"); } catch (InterruptedException e) { e.printStackTrace(); } return Integer.toString(value.getAndIncrement()); };
List<CompletableFuture<String>> stage1 = IntStream.range(0, 10).mapToObj(val -> CompletableFuture.supplyAsync(process)).collect(Collectors.toList());
List<CompletableFuture<String>> stage2 = stage1.stream().map(Test::appendNumber).collect(Collectors.toList());
List<CompletableFuture<String>> stage3 = stage2.stream().map(Test::printIfCancelled).collect(Collectors.toList());
CompletableFuture<Void> awaitAll = CompletableFuture.allOf(stage2.toArray(new CompletableFuture[0]));
try
{
/*Wait 1/2 the time, some should be complete. Some not complete -> TimeoutException*/
awaitAll.get(maxSleepTime / 2, TimeUnit.MILLISECONDS);
}
catch(TimeoutException ex)
{
for(CompletableFuture<String> toCancel : stage2)
{
boolean irrelevantValue = false;
if(!toCancel.isDone())
toCancel.cancel(irrelevantValue);
else
calculatedValues.add(toCancel.join());
}
}
System.out.println("All futures Cancelled! But some Stage 1's may still continue printing anyways.");
System.out.println("Values returned as of cancellation: " + calculatedValues);
Thread.sleep(maxSleepTime);
}
private static CompletableFuture<String> appendNumber(CompletableFuture<String> baseFuture)
{
return baseFuture.thenApply(val -> { System.out.println("Stage 2 Running"); return "#" + val; });
}
private static CompletableFuture<String> printIfCancelled(CompletableFuture<String> baseFuture)
{
return baseFuture.thenApply(val -> { System.out.println("Stage 3 Running!"); return val; }).exceptionally(ex -> { System.out.println("Stage 3 Cancelled!"); return ex.getMessage(); });
}
If it is necessary to cancel the upstream process (ex: cancel some network call), custom handling will be needed.
After calling cancel you cannot join the furure, since you get an exception.
One way to terminate the computation is to let it have a reference to the future and check it periodically: if it was cancelled abort the computation from inside.
This can be done if the computaion is a loop where at each iteration you can do the check.
Do you need it to be a CompletableFuture? Cause another way is to avoid to use a CompleatableFuture, and use a simple Future or a FutureTask instead: if you execute it with an Executor calling future.cancel(true) will terminate the computation if possbile.
Answerring to the question: "call join(), will I get the result immediately".
No you will not get it immediately, it will hang and wait to complete the computation: there is no way to force a computation that takes a long time to complete in a shorter time.
You can call future.complete(value) providing a value to be used as default result by other threads that have a reference to that future.
So I have a couple futures which I want to run, even if some fail I'd like all to have a chance to run. So if I do:
CompletableFuture.allOf(futures).join()
Will that be the case? My reasoning is that every future would have its own queed job in its executor and therefore all would run provided the main thread doesn't finish first. My issue is that I specifically .join() on .allOf() so my application doesnt end before running everything
So allOf() semantics confuse me: Will the future return complete when all of the passed futures complete regardless if successful? Or will it complete a failed future if it sees one failed without waiting for the rest?
EDIT
To illustrate my question further, does .allOf behaves like this:
Stream.of(futures).forEach(future -> {
try {
future.join()
} catch (Throwable e) {
//dont throw, we want to join the rest
}
})
Or does it behaves like the following:
Stream.of(futures).forEach(future -> {
try {
future.join()
} catch (Throwable e) {
throw e; //All other remaining .join() wont run
}
})
Which is it? first or second case? Since I want the first case thats what I'm using on my code temporarily, but I'd like to use allOf() if possible because its more aesthetic
Thanks!
Yes, each future will be independently attempted for completion.
I think you are also trying to understand how the control flows in various scenarios. I have come up with 4 scenarios :
A future where failure shall happens due to an unhandled exception
A future which shall be explicitly marked as failed with a completeExceptionally AND has an exceptionally block at its tail.
A future which shall be explicitly marked as failed with a completeExceptionally AND does not have an exceptionally block at its tail.
A future that shall complete to success.
//CASE 1
// A future that shall fail due to an unandled exception in its run
// and has an exceptionally block at its tail
CompletableFuture<Void> unhandledFailureFutureWithExceptionHandler =
CompletableFuture.runAsync(() -> {
throw new RuntimeException("Exception in unhandledFailureFutureWithExceptionHandler");
});
unhandledFailureFutureWithExceptionHandler = unhandledFailureFutureWithExceptionHandler
.exceptionally(throwable -> {
// Handling exception for this future
// HANDLING POINT 1
System.out.println("Handling exception at HANDLING POINT FOR CASE 1,
failure message is : " + throwable.getMessage());
return null;
});
//CASE 2
//A future that shall fail and has an exceptionally block at its tail
CompletableFuture<Void> failedFutureWithExceptionHandler = new CompletableFuture<>();
failedFutureWithExceptionHandler.completeExceptionally(
new RuntimeException("Exception in failedFutureWithExceptionHandler")
);
failedFutureWithExceptionHandler = failedFutureWithExceptionHandler.exceptionally(throwable -> {
// Handling exception for this future
// HANDLING POINT 2
System.out.println("Handling exception at HANDLING POINT FOR CASE 2,
failure message is : " + throwable.getMessage());
return null;
});
//CASE 3
//A future that shall fail and has no exceptionally block at its tail
CompletableFuture<Void> failedFutureWithoutExceptionHandler = new CompletableFuture<>();
failedFutureWithoutExceptionHandler.completeExceptionally(
new RuntimeException("Exception in failedFutureWithoutExceptionHandler")
);
//CASE 4
//A future that shall succeed and print a message to console
CompletableFuture<Void> successFuture = CompletableFuture.runAsync(() ->
System.out.println("CASE 4 : Running successFuture")
);
CompletableFuture.allOf(unhandledFailureFutureWithExceptionHandler,
failedFutureWithExceptionHandler, failedFutureWithoutExceptionHandler, successFuture)
.exceptionally(throwable -> {
// Handling exception if ANY of the futures that did not have its own exceptionally block
// In this case the exception of `failedFutureWithoutExceptionHandler` will be handled here
// HANDLING POINT 3
System.out.println("Handling exception at HANDLING POINT FOR CASE 3,
failure message is : " + throwable.getMessage());
return null;
}).join();
The output produced on the console is
Handling exception at HANDLING POINT FOR CASE 1, failure message is : java.lang.RuntimeException: Exception in unhandledFailureFutureWithExceptionHandler
Handling exception at HANDLING POINT FOR CASE 2, failure message is : Exception in failedFutureWithExceptionHandler
CASE 4 : Running successFuture
Handling exception at HANDLING POINT FOR CASE 3, failure message is : java.lang.RuntimeException: Exception in failedFutureWithoutExceptionHandler
As you can see if a future throws an unhandled error as in case 1, if it has a exceptionally block chained to its tail, the exception shall be handled at that point
As for case 2, in case where the future is marked as failed with completeExceptionally, if the future has a handler chained to its tail, then the exceptionally block shall be handled by that block
In case 3, the future is marked as failed and does not have an exceptionally block, thus it shall be handled by the exceptionally block at the next level, in this case it is the exceptionally block of the allOf().
As you can see, case 4 runs to completion and the message gets print on the console irrespective of the failures of the other futures.
My intuition is that the following code is wrong. I believe because join() is being used, any exceptions throw while completing the futures will be unchecked. Then when get() is called, there will be no checked exceptions, no logging of any errors, and difficulty diagnosing errors during failure.
List<CompletableFuture> list = ImmutableList.of(future1, future2);
CompletableFuture.allOf(list.toArray(new CompletableFuture[list.size()])).join();
try {
result1 = future1.get();
result2 = future2.get();
} catch (InterruptedException | ExecutionException e) {
// will this ever run if join() is already called?
}
I have looked through the documentation for CompletableFuture but haven't found the exact answer to my question. I am asking here and will then go read through the source code.
The only why I can see that the catch block code would run is if somehow checked exceptions can be saved in some execution context and not thrown in join() (or thrown wrapped by an unchecked exception), and then throw again in some form after get(). This seems unlikely to me.
So my ultimate question is, will the catch block code ever run?
Both the join and the get method are blocking method that relies on completion signals and returns the result T. Processing the piece of code as in question :-
On one hand, InterruptedException could be thrown while the thread is interrupted in the process of waiting as we do a get, the wait here is already completed by the join method.
Also, as stated in the join method documentation
/**
* ... if a
* computation involved in the completion of this
* CompletableFuture threw an exception, this method throws an
* (unchecked) {#link CompletionException} with the underlying
* exception as its cause.
*/
So, on the other hand, the ExecutionException for futureN.get() in your case could only be thrown when and if the future completed exceptionally. Since the future if executed exceptionally would end up in throwing a CompletionException for the join call, it wouldn't reach the catch block ever or for that sake try block either.
Yes, the code would never be reached, but that doesn't make the "code wrong".
First, let's just try it out...
CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> {
throw new IllegalArgumentException();
});
try
{
CompletableFuture.allOf(future1).join();
}
catch (Exception e1)
{
System.out.println("I'd exit here."); // *1
}
try
{
future1.get();
}
catch (InterruptedException | ExecutionException e)
{
System.out.println("Entered!");
}
Since you didn't do the try/catch "*1", the Exception would cause the method to exit and the get() would never be reached; so the second catch clause would never be executed.
However, the catch is still necessary because it's for the compiler, which has no way of knowing the previous call sequence.
The more straightforward way of doing this would be like this anyway:
CompletableFuture<Integer> future1 = CompletableFuture.supplyAsync(() -> {
throw new IllegalArgumentException();
});
try
{
CompletableFuture.allOf(future1).join();
future1.get();
}
catch (CompletionException e1) // this is unchecked, of course
{
System.out.println("Exception when joining");
}
catch (InterruptedException | ExecutionException e)
{
System.out.println("Exception when getting");
}
I would like to know if a one-liner exists for creating a CompletableFuture from a synchron method call. If no, why?
Long version:
final CompletableFuture<ReturnType> future = new CompletableFuture<>();
final String parameters = "hello";
ReturnType result;
try {
result = syncMethodCall(parameters);
} catch (Exception e) {
future.completeExceptionally(e);
}
future.complete(result);
return future;
Short desired version (or kind):
final String parameters = "hello";
return CompletableFuture.superMethod(() -> {syncMethodCall(parameters)});
Since you accepted an answer that performs an asynchronous call, it’s unclear why you asked for a “synchron method call” in the first place. The task of performing an asynchronous method invocation is quite easy with CompletableFuture:
String parameters="hello";
return CompletableFuture.supplyAsync(() -> syncMethodCall(parameters));
If your intention was to enforce the future to be already completed upon returning, it’s easy to enforce:
String parameters="hello";
CompletableFuture<ReturnType> f = CompletableFuture.supplyAsync(
() -> syncMethodCall(parameters));
f.handle((x,y) -> null).join();
return f;
The handle stage before the join ensures that in case syncMethodCall threw an exception, join won’t, as that seems to be your intention. But the handle stage is not returned, instead, the original future with the recorded exception will be returned.
Note that there’s a trick to do everything within the caller’s thread with the current implementation:
return CompletableFuture.completedFuture("hello")
.thenApply(parameters -> syncMethodCall(parameters));
The function passed to thenApply will be evaluated immediately when the future is already completed. But still, exceptions thrown by syncMethodCall are recorded in the returned future. So the outcome is identical to the “long version” of your question.
Since you want that your CompletableFuture is completed with a result of some method call, and you do not want to complete that CompletableFuture yourself - then you need not CompletableFuture - any Future implementation would be ok.
For example,
T function(parameters) {
return new T();
}
T res1 = function(parameters); // sync call
Future<T> f = ForkJoinPool.commonPool.submit(() -> function(parameters)); // async call
T res2 = f.get();
assert(res1.equals(res2));
I've grown desperate all night on this problem and I have not found help during online research, so here we go.
I want to do an optimization process which is meant to be interrupted at a time that is being determined on runtime. Once the interrupt is thrown, I want the best result that has been calculated until that moment to be returned.
My Idea was to put the calculations into a Callable. Because Callables can return results and also - at least I thought - be interrupted. My call() method would be able to return my best result when an interrupt is thrown. But apparently, the only way to force an interrupt into the Callable is to do task.cancel(true); which then throws a CancellationException before result = task.get(); can retrieve the result.
A rough scetch of my code:
SearchCallable myCallable = new myCallable(...);
ExecutorService service = Executors.newFixedThreadPool(1);
Future<int[]> task = service.submit(myCallable);
try {
Thread.sleep(getTimeToCalculate(...));
} catch (InterruptedException e) {[...]}
task.cancel(true);
try {
result = task.get();
} catch(InterruptedException ie){[...]
} catch (ExecutionException ee) {[...]}
myCallable looks somewhat like this:
public class myCallable implements Callable<Object> {
public myCallable(...){
[...]
}
public Object call(){
return anObjectOfAnotherClass.saidCalculations();
}
}
Where an auxiliary method which does a lot of recursion contains this:
if(Thread.interrupted()){
throw new InterruptedException();
}
And said auxiliary method catches this InterruptedException and returns it's best result so far, so myCallable gets this result and actually should return it.
So, how can I get the interrupt in there and still get my result? Or is there some completely different way to implement my original idea?
So, there is one thread performing the computation; this thread is interrupted and the "best result" is what it could come up with.
Then you can, instead of a Callable, use a Runnable and pass a reference to a structure bearing the result when you initialize it.
You can then submit that runnable to your thread pool; when it is "done with its work" (either it is really done, or it was interrupted), you'll just have to read the data in the reference you passed to your Runnable as an argument.
EDIT Since the result of the computation is a( reference to a)n object, I suggest the use of an AtomicReference.