Timeout with default value in Java 8 CompletableFuture - java

Suppose I have some async computation, such as:
CompletableFuture
.supplyAsync(() -> createFoo())
.thenAccept(foo -> doStuffWithFoo(foo));
Is there a nice way to provide a default value for foo if the async supplier times out according to some specified timeout? Ideally, such functionality would attempt to cancel the slow-running supplier as well. For example, is there standard library functionality that is similar to the following hypothetical code:
CompletableFuture
.supplyAsync(() -> createFoo())
.acceptEither(
CompletableFuture.completedAfter(50, TimeUnit.MILLISECONDS, DEFAULT_FOO),
foo -> doStuffWithFoo(foo));
Or perhaps even better:
CompletableFuture
.supplyAsync(() -> createFoo())
.withDefault(DEFAULT_FOO, 50, TimeUnit.MILLISECONDS)
.thenAccept(foo -> doStuffWithFoo(foo));
I know about get(timeout, unit), but am wondering if there's a nicer standard way of applying a timeout in an asynchronous and reactive fashion as suggested in the code above.
EDIT: Here's a solution that's inspired by Java 8: Mandatory checked exceptions handling in lambda expressions. Why mandatory, not optional?, but unfortunately it blocks a thread. If we rely on createFoo() to asynchronously check for timeout and throw its own timeout exception it would work without blocking a thread, but would place more burden on the creator of the supplier and would still have the cost of creating an exception (which can be expensive without "fast throw")
static <T> Supplier<T> wrapped(Callable<T> callable) {
return () -> {
try {
return callable.call();
} catch (RuntimeException e1) {
throw e1;
} catch (Throwable e2) {
throw new RuntimeException(e2);
}
};
}
CompletableFuture
.supplyAsync(wrapped(() -> CompletableFuture.supplyAsync(() -> createFoo()).get(50, TimeUnit.MILLISECONDS)))
.exceptionally(e -> "default")
.thenAcceptAsync(s -> doStuffWithFoo(foo));

CompletableFuture.supplyAsync is just a helper method that creates a CompletableFuture for you, and submits the task to the ForkJoin Pool.
You can create your own supplyAsync with your requirements like this:
private static final ScheduledExecutorService schedulerExecutor =
Executors.newScheduledThreadPool(10);
private static final ExecutorService executorService =
Executors.newCachedThreadPool();
public static <T> CompletableFuture<T> supplyAsync(
final Supplier<T> supplier, long timeoutValue, TimeUnit timeUnit,
T defaultValue) {
final CompletableFuture<T> cf = new CompletableFuture<T>();
// as pointed out by Peti, the ForkJoinPool.commonPool() delivers a
// ForkJoinTask implementation of Future, that doesn't interrupt when cancelling
// Using Executors.newCachedThreadPool instead in the example
// submit task
Future<?> future = executorService.submit(() -> {
try {
cf.complete(supplier.get());
} catch (Throwable ex) {
cf.completeExceptionally(ex);
}
});
//schedule watcher
schedulerExecutor.schedule(() -> {
if (!cf.isDone()) {
cf.complete(defaultValue);
future.cancel(true);
}
}, timeoutValue, timeUnit);
return cf;
}
Creating the CompletableFuture with that helper is as easy as using the static method in CompletableFuture:
CompletableFuture<String> a = supplyAsync(() -> "hi", 1,
TimeUnit.SECONDS, "default");
To test it:
a = supplyAsync(() -> {
try {
Thread.sleep(2000);
} catch (InterruptedException e1) {
// ignore
}
return "hi";
}, 1, TimeUnit.SECONDS, "default");

In Java 9, there will be completeOnTimeout(T value, long timeout, TimeUnit unit), which does what you want, although it does not cancel the slow supplier.
There is also a orTimeout(long timeout, TimeUnit unit), which completes exceptionally in case on a timeout.

DZone has a good article how to solve this: https://dzone.com/articles/asynchronous-timeouts
I'm not sure about the copyright of the code, hence I can't copy it here. The solution is very much like the one from Dane White but it uses a thread pool with a single thread plus schedule() to avoid wasting a thread just to wait for the timeout.
It also throws a TimeoutException instead of returning a default.

I think you'll always need an extra thread monitoring when its time to supply the default value. I'd probably go the route of having two supplyAsync calls, with the default wrapped in a utility API, linked by an acceptEither. If you'd rather wrap your Supplier, then you could use a utility API that makes the 'either' call for you:
public class TimeoutDefault {
public static <T> CompletableFuture<T> with(T t, int ms) {
return CompletableFuture.supplyAsync(() -> {
try {
Thread.sleep(ms);
} catch (InterruptedException e) { }
return t;
});
}
public static <T> Supplier<T> with(Supplier<T> supplier, T t, int ms) {
return () -> CompletableFuture.supplyAsync(supplier)
.applyToEither(TimeoutDefault.with(t, ms), i -> i).join();
}
}
CompletableFuture<Void> future = CompletableFuture
.supplyAsync(Example::createFoo)
.acceptEither(
TimeoutDefault.with("default", 1000),
Example::doStuffWithFoo);
CompletableFuture<Void> future = CompletableFuture
.supplyAsync(TimeoutDefault.with(Example::createFoo, "default", 1000))
.thenAccept(Example::doStuffWithFoo);

There's no standard library method for constructing a CompletableFuture supplied with a value after a timeout. That said, it's really simple to roll your own with minimal resource overhead:
private static final ScheduledExecutorService EXECUTOR
= Executors.newSingleThreadScheduledExecutor();
public static <T> CompletableFuture<T> delayedValue(final T value,
final Duration delay) {
final CompletableFuture<T> result = new CompletableFuture<>();
EXECUTOR.schedule(() -> result.complete(value),
delay.toMillis(), TimeUnit.MILLISECONDS);
return result;
}
It can be used with the "either" methods of CompleteableFuture:
accceptEither, acceptEitherAsync
applyToEither, applyToEitherAsync
runAfterEither, runAfterEitherAsync
One application is using a cached value if a remote service call exceeds some latency threshold:
interface RemoteServiceClient {
CompletableFuture<Foo> getFoo();
}
final RemoteServiceClient client = /* ... */;
final Foo cachedFoo = /* ... */;
final Duration timeout = /* ... */;
client.getFoos()
.exceptionally(ignoredException -> cachedFoo)
.acceptEither(delayedValue(cachedFoo, timeout),
foo -> /* do something with foo */)
.join();
In case the remote client call completes exceptionally (e.g. SocketTimeoutException), we can fail fast and use the cached value immediately.
CompletableFuture.anyOf(CompletableFuture<?>...) can be combined with this delayedValue primitive to wrap a CompletableFuture with the above semantics:
#SuppressWarnings("unchecked")
public static <T> CompletableFuture<T> withDefault(final CompletableFuture<T> cf,
final T defaultValue,
final Duration timeout) {
return (CompletableFuture<T>) CompletableFuture.anyOf(
cf.exceptionally(ignoredException -> defaultValue),
delayedValue(defaultValue, timeout));
}
This nicely simplifies the remote service call example above:
withDefault(client.getFoos(), cachedFoo, timeout)
.thenAccept(foo -> /* do something with foo */)
.join();
CompletableFutures are more accurately termed promises, as they decouple creation of the Future from its completion. Be sure to use dedicated thread pools for heavy CPU work. To create a CompletableFuture for an expensive computation, you should use the CompletableFuture#supplyAsync(Supplier, Executor) overload, as the #supplyAsync(Supplier) overload defaults to the common ForkJoinPool. The returned CompletableFuture could not cancel its task, as this functionality isn't exposed by the Executor interface. More generally, dependent CompletableFutures don't cancel their parents, e.g. cf.thenApply(f).cancel(true) does not cancel cf. I'd recommend sticking to the Futures returned by ExecutorServices if you need that functionality.

Related

Concurrent programming in Java with return values

I have a problem with concurrent programming in Java. I am working on my bachelor thesis and I have to make several methods which will return me a String value. In the Futures TriggerMessageFututre and getMeterValuesFuture is a process running which takes between 1-5 seconds and returns a String Value when it's finished.
The problem is now that future.get() is blocking my main thread. I want to call the TriggerMessage and the getMeterValue methode in my main without blocking my main thread and get their answer as a return value when they are finished. I wasn't able to find a way to solve my problem, because either it was a solution without return value or it was a solution which blocked the thread.
private String TriggerMessage(String Messagetyp) throws InterruptedException, ExecutionException{
Future<String> future = new communicator().TriggerMessageFuture(queue,centralSystem,Messagetyp);
while(!future.isDone()) {
System.out.println("[TriggerMessage]: Calculating... ");
Thread.sleep(500);
}
String result = future.get(); //blocking
return result;
}
private String getMeterValue(String key) throws Exception{
Future<String> future = new communicator().getMeterValueFuture(queue,centralSystem,key);
while(!future.isDone()) {
System.out.println("[getMeterValue]: Calculating...");
Thread.sleep(500);
}
String result = future.get(); //blocking
return result;
}
It depends on what main thread are you referring to, plus if you can use CompletableFutures instead of plain old Java Futures.
Using the main(String[] args) thread
It's not possible to do it without any form of blocking. If you are not blocking on get, you'll have to block on a BlockingQueue implementation, otherwise the main thread just ends.
Using the Swing Event Dispatch thread
You'd need to submit a continuation task which is not possible with Future.get from the outside. So either you include this submission inside the task Future has been created for, or switch to CompletableFuture
ExecutorService exec = ...
Future<?> future = exec.submit(() -> {
var value = someCalculation();
SwingUtilities.invokeLater(() -> {
useValueOnEDT(value);
});
});
or
CompletableFuture<ValueType> cf = ...
cf.whenComplete((value, error) -> {
SwingUtilities.invokeLater(() -> {
if (error != null) {
handleErrorOnEdt(error);
} else {
useValueOnEDT(value);
}
});
});
Android Main Thread
The idea is the same as with Swing, but you'll have to use a Handler
// given value
new Handler(Looper.getMainLooper()).post(() -> {
useValueOnMainLooper(value);
});
You can wrap the Future into a CompletableFuture like so
static <T> CompletableFuture<T> from(Future<T> future) {
var delegate = new CompletableFuture<T>();
CompletableFuture.runAsync(() -> {
try {
delegate.complete(future.get());
} catch (Throwable e) {
delegate.completeExceptionally(e);
}
});
return delegate;
}
And then use that CompletableFuture to asynchronously handle the completion via its various then... and when... methods.

Vertx: executeBlocking() vs Future. What's the difference?

Vertx docs suggests to use executeBlocking() method when one needs to call blocking API. On the other hand Vertx also offers a notion of Future which basically do the same thing. But the executeBlocking() method isn't static. It is also not a simple wrapper around Future, and if you look at its implementation you'll see that it's pretty complex. What's the difference between these two?
Assume that I want to execute some long running task in an async way. Is there any difference between these two methods?
method 1:
doTheJob() {
Future<Void> future = Future.future();
executeLongRunningBlockingOperation();
future.complete();
return future;
}
doTheJob().setHandler(asyncResult -> {
// ... handle result
});
method 2:
vertx.executeBlocking(future -> {
executeLongRunningBlockingOperation();
future.complete();
}, res -> {
// ... handle result
});
Your first example is not a correct usage of Future. The call to executeLongRunningBlockingOperation() will block the main thread until that method has completed — i.e. nothing else can happen until the blocking operation finishes. In your second example the blocking call is spun off into a background thread and other things continue to happen while it executes.
To illustrate this with a more complete example, this code:
public void executeLongRunningBlockingOperation() {
Thread.sleep(5000);
}
public Future<Void> doTheJob() {
System.out.println("Doing the job...");
Future<Void> future = Future.future();
executeLongRunningBlockingOperation();
// this line will not be called until executeLongRunningBlockingOperation returns!
future.complete();
// nor will this method! This means that the method won't return until the long operation is done!
return future;
}
public static void main(String[] args) {
doTheJob().setHandler(asyncResult -> {
System.out.println("Finished the job");
});
System.out.println("Doing other stuff in the mean time...");
}
Will produce the following output:
Doing the job...
Finished the job
Doing other stuff in the mean time...
Whereas this code (using the executeBlocking):
...
public Future<Void> doTheJob() {
System.out.println("Doing the job...");
Future<Void> future = Future.future();
Vertx vertx = Vertx.vertx();
vertx.executeBlocking(call -> {
executeLongRunningBlockingOperation();
call.complete;
}, result -> {
// this will only be called once the blocking operation is done
future.complete();
});
// this method returns immediately since we are not blocking the main thread
return future;
}
...
Will produce:
Doing the job...
Doing other stuff in the mean time...
Finished the job
If you'd like to develop a better understanding of Vert.x I'd recommend the following hands-on tutorials:
https://vertx.io/docs/guide-for-java-devs/
http://escoffier.me/vertx-hol/

CompletableFuture long running task with time out would it hold thread given composed with timeout future?

In the following code intention is to achieve asynchronous execution of a task provided it runs in less than 100 ms else timeout exception from other thread would be thrown ,
Question : What happens to the thread that is executing asynchronously for more than 100 ms , would it be released ? or it would wait for the task to complete without throwing exception ? ( wrote the code thinking that acceptEither would terminate the long running task once it encounters the timeOutException from the other future)
private static final ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
public static <T> CompletableFuture<T> failAfter(long longValue) {
final CompletableFuture<T> timeoutFuture = new CompletableFuture<>();
scheduler.schedule(() -> {
final TimeoutException ex = new TimeoutException("Timing out");
return timeoutFuture.completeExceptionally(ex);
}, longValue, TimeUnit.MILLISECONDS);
return timeoutFuture;
}
final CompletableFuture<CustomResponse> CustomResponseFuture = CompletableFuture.supplyAsync(() -> object.taks()).
exceptionally(ex -> {
System.out.println("help");
return new "Hello";
});
CustomResponseFuture
.acceptEither(failAfter(100l), TesFutureStuff::myNewMethod)
.exceptionally(throwable -> {
System.out.println("failure "+throwable.getMessage());
return null;
})/*.getNow(null )*/;
If you just want a task that terminates after a specific amount of time, you don’t need CompletableFuture. Just create an ExecutorService, and call its invokeAny method.
If you insist on using CompletableFuture, you can use its get and cancel methods:
CompletableFuture<CustomResponse> future = CompletableFuture.supplyAsync(() -> object.task());
try {
CustomResponse response = future.get(100, TimeUnit.MILLISECONDS);
// process response here
} catch (ExecutionException e) {
throw new RuntimeException(e);
} catch (TimeoutException e) {
System.out.println(e);
future.cancel(true);
}
Update:
To do the whole thing in the background, submit the invokeAny call to the same ExecutorService, but make sure the ExecutorService is not single threaded. There are many choices: Executors.newFixedThreadPool(2), Executors.newWorkStealingPool(), Executors.newCachedThreadPool, or even ForkJoinPool.commonPool().
For the CompletableFuture approach, I just noticed that as of Java 9, CompletableFuture adds an orTimeout method:
future.orTimeout(100, TimeUnit.MILLISECONDS);

Get individual results from CompletableFuture.allof()

I have a class which issues concurrent requests to two dependent services using CompletableFutures.
My code looks like this:
#Builder
#Slf4j
public class TestClass {
#NonNull private final ExecutorService threadPool = Executors.newFixedThreadPool(2);
#NonNull private final dependency1Client;
#NonNull private final dependency2Client;
public void myMethod() {
RequestObject1 firstDependencyRequest = RequestObject1.builder()
.attribute1("someValue")
.attribute2("secondValue");
CompletableFuture<ResultStructure1> future1 = CompletableFuture.supplyAsync(() -> dependency1Client.call(firstDependencyRequest), threadPool);
RequestObject2 secondDependencyRequest = RequestObject2.builder()
.attribute1("someValue")
.attribute2("secondValue");
CompletableFuture<ResultStructure2> future2 = CompletableFuture.supplyAsync(() -> dependency2Client.call(secondDependencyRequest), threadPool);
try {
CompletableFuture finalFuture = CompletableFuture.allOf(future1, future2);
} catch (ExecutionException|InterruptedException e) {
log.error("Exception calling dependency", e);
throw new RuntimeException(e);
}
}
}
I need the results from the two calls to the dependent services. How do I get them without performing a blocking call? I was initially thinking that I'd do future1 .get(), but that's a blocking call and I'll have to wait until I have the results from the first API call.
Is there a way to obtain the results from both the calls?
As the JavaDoc of CompletableFuture.allOf() indicates:
Otherwise, the results, if any, of the given CompletableFutures are not reflected in the returned CompletableFuture, but may be obtained by inspecting them individually.
What this means is indeed that you have to call join() or get() on them. It will not block if you do that in the chain after your allOf(), since it already guarantees that all of them are already completed.
Note that in your particular case, if you only have 2 futures, it is probably simpler to use thenCombine() which gives you access to the 2 results more easily.

How do I start a CompletableFuture without blocking and do something when it's done?

The CompletableFuture API is fairly intimidating, lot's of accepts, and thens and other things; it's hard to tell why different options exist.
CompletableFuture<?> future = CompletableFuture.supplyAsync(() ->..., executor)
future.startNonBlocking...( (...) -> { callback behavior done when complete }
I'm basically trying to mimic a new Thread(() -> dostuff).start() but with better thread pooling, error handling, etc. Note: I don't actually need the Runnable interface here, I'm generifying a piece of existing code.
what's the right way to start my asynchronous task and execute behavior when it's complete? or handle an exception that is thrown?
Here's a simple async callback:
CompletableFuture.supplyAsync(() -> [result]).thenAccept(result -> [action]);
Or if you need error handling:
CompletableFuture.supplyAsync(() -> [result]).whenComplete((result, exception) -> {
if (exception != null) {
// handle exception
} else {
// handle result
}
});
new Thread(() -> dostuff).start()
means that dostuff implements Runnable, so you may use
static CompletableFuture<Void> runAsync(Runnable runnable)
static CompletableFuture<Void> runAsync(Runnable runnable, Executor executor)
also.

Categories

Resources