I've been trying to setup a simple atomic completable future cache that takes a String key and a Callable class and caches the executions and the results. I know I could use caffeine but still want to understand how this can be done without race conditions while inserting and clearing.
In this simple class I have two simplified caches: an executions cache that keeps tracks of the callables that haven't finished running, and a results cache that keeps track of the results (this will eventually be an ehcache that overflows to disk)
public class AsyncCache {
ExecutorService executor = Executors.newFixedThreadPool(10);
ConcurrentHashMap<String, CompletableFuture<Object>> executions = new ConcurrentHashMap<>();
ConcurrentHashMap<String, Object> results = new ConcurrentHashMap<>();
public CompletableFuture<Object> get(String key, Callable<Object> callable) {
Object result = results.get(key);
if (result != null) {
return CompletableFuture.completedFuture(result);
}
return executions.computeIfAbsent(key, k -> {
CompletableFuture<Object> future = CompletableFuture.supplyAsync(() -> {
try {
return callable.call();
} catch (Exception e) {
throw new CompletionException(e);
}
}, executor);
return future.whenComplete((Object r, Throwable t) -> {
if (executions.remove(k) != null) {
results.put(k, result);
}
});
});
}
public void clear() {
results.clear();
executions.clear();
}
}
I believe that this code has two problems. First, there is a synchronization problem in the lines:
if (executions.remove(k) != null) {
results.put(k, result);
}
In between remove(k) and results.put(k, result) there can be a new get call for the same key that is not already in results and has been removed from executions, thus triggering a new callable execution, when the result was about to be placed in the results cache.
Second, there is another synchronization problem in the lines:
results.clear();
executions.clear();
In between both clear() there can be a new get call that would not get result from the results map but would get a stalled response from the executions map.
Any ideas on how to fix this without naively synchronizing everything.
Edit.
What if I introduce a lock per key to guard against read and writes? Something like this:
ConcurrentMap<String, ReadWriteLock> locks = new ConcurrentHashMap<String, ReadWriteLock>();
public CompletableFuture<Object> get1(String key, Callable<Object> callable) {
ReadWriteLock reading = locks.computeIfAbsent(key, r -> new ReentrantReadWriteLock());
reading.readLock().lock();
try {
Object result = results.get(key);
if (result != null) {
return CompletableFuture.completedFuture(result);
}
return executions.computeIfAbsent(key, k -> {
CompletableFuture<Object> future = CompletableFuture.supplyAsync(() -> {
try {
return callable.call();
} catch (Exception e) {
throw new CompletionException(e);
}
}, executor);
return future.whenComplete((Object r, Throwable t) -> {
ReadWriteLock writing = locks.computeIfAbsent(k, w -> new ReentrantReadWriteLock());
writing.writeLock().lock();
try {
if (executions.remove(k) != null) {
results.put(k, r);
}
} finally {
writing.writeLock().unlock();
locks.remove(k);
}
});
});
} finally {
reading.readLock().unlock();
locks.remove(key);
}
}
This would still leave with questions regarding how to write the clear() method.
This is the code I ended up using. I have gone through many revisions but can't find any obvious deadlocks or race conditions. I'm going leave it here just in case it becomes useful for somebody else.
public class AsyncCache {
ExecutorService executor = Executors.newFixedThreadPool(10);
ConcurrentHashMap<String, CompletableFuture<Object>> executions = new ConcurrentHashMap<>();
ReentrantReadWriteLock guard = new ReentrantReadWriteLock();
MutableConfiguration<String, Object> configuration = new MutableConfiguration<>();
Cache<String, Object> results = Caching.getCachingProvider().getCacheManager().createCache("results", configuration);
public CompletableFuture<Object> get(String key, Callable<Object> callable) {
guard.readLock().lock();
try {
// Attempt to get from the cache first. Only pay attention to
// the cache eviction policies.
Object result = results.get(key);
if (result != null) {
return CompletableFuture.completedFuture(result);
}
// Attempt to get from the current executions second. Make sure
// that the cache and executions is guarded by a read write lock.
return executions.computeIfAbsent(key, k -> {
CompletableFuture<Object> future = CompletableFuture.supplyAsync(() -> {
try {
return callable.call();
} catch (Exception e) {
throw new CompletionException(e);
}
}, executor);
return future.whenComplete((Object r, Throwable t) -> {
guard.writeLock().lock();
try {
if (executions.remove(k) != null) {
if (r != null) {
results.put(k, r);
}
}
} finally {
guard.writeLock().unlock();
}
});
});
} finally {
guard.readLock().unlock();
}
}
public void clear() {
// Guard the cache and executions with a write lock.
guard.writeLock().lock();
try {
executions.clear();
results.clear();
} finally {
guard.writeLock().unlock();
}
}
}
I'm still not sure how to check if this is overly restrictive (locking more than needed). For my use case, the callables can take from 100 to 3000 milliseconds, and the clear method can be called every 15 minutes or so.
Perhaps I don't even need the executions to be a ConcurrentHashMap since the read and writes are protected.
Related
Java 8 introduces CompletableFuture, a new implementation of Future that is composable (includes a bunch of thenXxx methods). I'd like to use this exclusively, but many of the libraries I want to use return only non-composable Future instances.
Is there a way to wrap up a returned Future instances inside of a CompleteableFuture so that I can compose it?
If the library you want to use also offers a callback style method in addition to the Future style, you can provide it a handler that completes the CompletableFuture without any extra thread blocking. Like so:
AsynchronousFileChannel open = AsynchronousFileChannel.open(Paths.get("/some/file"));
// ...
CompletableFuture<ByteBuffer> completableFuture = new CompletableFuture<ByteBuffer>();
open.read(buffer, position, null, new CompletionHandler<Integer, Void>() {
#Override
public void completed(Integer result, Void attachment) {
completableFuture.complete(buffer);
}
#Override
public void failed(Throwable exc, Void attachment) {
completableFuture.completeExceptionally(exc);
}
});
completableFuture.thenApply(...)
Without the callback the only other way I see solving this is to use a polling loop that puts all your Future.isDone() checks on a single thread and then invoking complete whenever a Future is gettable.
There is a way, but you won't like it. The following method transforms a Future<T> into a CompletableFuture<T>:
public static <T> CompletableFuture<T> makeCompletableFuture(Future<T> future) {
if (future.isDone())
return transformDoneFuture(future);
return CompletableFuture.supplyAsync(() -> {
try {
if (!future.isDone())
awaitFutureIsDoneInForkJoinPool(future);
return future.get();
} catch (ExecutionException e) {
throw new RuntimeException(e);
} catch (InterruptedException e) {
// Normally, this should never happen inside ForkJoinPool
Thread.currentThread().interrupt();
// Add the following statement if the future doesn't have side effects
// future.cancel(true);
throw new RuntimeException(e);
}
});
}
private static <T> CompletableFuture<T> transformDoneFuture(Future<T> future) {
CompletableFuture<T> cf = new CompletableFuture<>();
T result;
try {
result = future.get();
} catch (Throwable ex) {
cf.completeExceptionally(ex);
return cf;
}
cf.complete(result);
return cf;
}
private static void awaitFutureIsDoneInForkJoinPool(Future<?> future)
throws InterruptedException {
ForkJoinPool.managedBlock(new ForkJoinPool.ManagedBlocker() {
#Override public boolean block() throws InterruptedException {
try {
future.get();
} catch (ExecutionException e) {
throw new RuntimeException(e);
}
return true;
}
#Override public boolean isReleasable() {
return future.isDone();
}
});
}
Obviously, the problem with this approach is, that for each Future, a thread will be blocked to wait for the result of the Future--contradicting the idea of futures. In some cases, it might be possible to do better. However, in general, there is no solution without actively wait for the result of the Future.
If your Future is the result of a call to an ExecutorService method (e.g. submit()), the easiest would be to use the CompletableFuture.runAsync(Runnable, Executor) method instead.
From
Runnbale myTask = ... ;
Future<?> future = myExecutor.submit(myTask);
to
Runnbale myTask = ... ;
CompletableFuture<?> future = CompletableFuture.runAsync(myTask, myExecutor);
The CompletableFuture is then created "natively".
EDIT: Pursuing comments by #SamMefford corrected by #MartinAndersson, if you want to pass a Callable, you need to call supplyAsync(), converting the Callable<T> into a Supplier<T>, e.g. with:
CompletableFuture.supplyAsync(() -> {
try { return myCallable.call(); }
catch (Exception ex) { throw new CompletionException(ex); } // Or return default value
}, myExecutor);
Because T Callable.call() throws Exception; throws an exception and T Supplier.get(); doesn't, you have to catch the exception so prototypes are compatible.
A note on exception handling
The get() method doesn't specify a throws, which means it should not throw a checked exception. However, unchecked exception can be used. The code in CompletableFuture shows that CompletionException is used and is unchecked (i.e. is a RuntimeException), hence the catch/throw wrapping any exception into a CompletionException.
Also, as #WeGa indicated, you can use the handle() method to deal with exceptions potentially being thrown by the result:
CompletableFuture<T> future = CompletableFuture.supplyAsync(...);
future.handle((ex,res) -> {
if (ex != null) {
// An exception occurred ...
} else {
// No exception was thrown, 'res' is valid and can be handled here
}
});
I published a little futurity project that tries to do better than the straightforward way in the answer.
The main idea is to use only one thread (and of course with not just a spin loop) to check all Futures states inside, which helps to avoid blocking a thread from a pool for each Future -> CompletableFuture transformation.
Usage example:
Future oldFuture = ...;
CompletableFuture profit = Futurity.shift(oldFuture);
Suggestion:
http://www.thedevpiece.com/converting-old-java-future-to-completablefuture/
But, basically:
public class CompletablePromiseContext {
private static final ScheduledExecutorService SERVICE = Executors.newSingleThreadScheduledExecutor();
public static void schedule(Runnable r) {
SERVICE.schedule(r, 1, TimeUnit.MILLISECONDS);
}
}
And, the CompletablePromise:
public class CompletablePromise<V> extends CompletableFuture<V> {
private Future<V> future;
public CompletablePromise(Future<V> future) {
this.future = future;
CompletablePromiseContext.schedule(this::tryToComplete);
}
private void tryToComplete() {
if (future.isDone()) {
try {
complete(future.get());
} catch (InterruptedException e) {
completeExceptionally(e);
} catch (ExecutionException e) {
completeExceptionally(e.getCause());
}
return;
}
if (future.isCancelled()) {
cancel(true);
return;
}
CompletablePromiseContext.schedule(this::tryToComplete);
}
}
Example:
public class Main {
public static void main(String[] args) {
final ExecutorService service = Executors.newSingleThreadExecutor();
final Future<String> stringFuture = service.submit(() -> "success");
final CompletableFuture<String> completableFuture = new CompletablePromise<>(stringFuture);
completableFuture.whenComplete((result, failure) -> {
System.out.println(result);
});
}
}
Let me suggest another (hopefully, better) option:
https://github.com/vsilaev/java-async-await/tree/master/com.farata.lang.async.examples/src/main/java/com/farata/concurrent
Briefly, the idea is the following:
Introduce CompletableTask<V> interface -- the union of the
CompletionStage<V> + RunnableFuture<V>
Warp ExecutorService to return CompletableTask from submit(...) methods (instead of Future<V>)
Done, we have runnable AND composable Futures.
Implementation uses an alternative CompletionStage implementation (pay attention, CompletionStage rather than CompletableFuture):
Usage:
J8ExecutorService exec = J8Executors.newCachedThreadPool();
CompletionStage<String> = exec
.submit( someCallableA )
.thenCombineAsync( exec.submit(someCallableB), (a, b) -> a + " " + b)
.thenCombine( exec.submit(someCallableC), (ab, b) -> ab + " " + c);
public static <T> CompletableFuture<T> fromFuture(Future<T> f) {
return CompletableFuture.completedFuture(null).thenCompose(avoid -> {
try {
return CompletableFuture.completedFuture(f.get());
} catch (InterruptedException e) {
return CompletableFuture.failedFuture(e);
} catch (ExecutionException e) {
return CompletableFuture.failedFuture(e.getCause());
}
});
}
The main idea goes like this:
Future<?> future = null;
return CompletableFuture.supplyAsync(future::get);
However, you will receive some warnings from your compiler.
So, here is the first option.
Future<?> future = null;
return CompletableFuture.supplyAsync(
()->{
try {
return future.get();
} catch (Exception e) {
throw new RuntimeException(e);
}
});
Second Option, hide the try...catch via casting the functional interface.
#FunctionalInterface
public interface MySupplier<T> extends Supplier<T> {
#Override
default T get() {
try {
return getInternal();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
T getInternal() throws Exception;
}
public static void main(String[] args) {
Future<?> future = null;
return CompletableFuture.supplyAsync((MySupplier<?>) future::get);
}
Third Option, find out some 3rd party lib which has provided such a functional interface.
See Also: Java 8 Lambda function that throws exception?
In my code I have to run a task that makes heavy use of recursion and parallel stream processing in order to go deep into a tree of possible games moves and decide what's the best move. This takes a lot of time, so to prevent the user from waiting for too long for the computer to "think" I want to set a time out of, say, 1000 milliseconds. If the best move is not found withing 1000 msec then the computer will play a random move.
My problem is that although I call cancel on Future (with may interrupt set to true), the task is not interrupted and the busy threads keep running in the background.
I tried to periodically check for isInterrupted() on the current and then try to bail out, but this didn't help.
Any ideas?
Below is my code:
public Move bestMove() {
ExecutorService executor = Executors.newSingleThreadExecutor();
Callable<Move> callable = () -> bestEntry(bestMoves()).getKey();
Future<Move> future = executor.submit(callable);
try {
return future.get(1000, TimeUnit.MILLISECONDS);
} catch (InterruptedException e) {
System.exit(0);
} catch (ExecutionException e) {
throw new RuntimeException(e);
} catch (TimeoutException e) {
future.cancel(true);
return randomMove();
}
return null;
}
private Move randomMove() {
Random random = new Random();
List<Move> moves = state.possibleMoves();
return moves.get(random.nextInt(moves.size()));
}
private <K> Map.Entry<K, Double> bestEntry(Map<K, Double> map) {
List<Map.Entry<K, Double>> list = new ArrayList<>(map.entrySet());
Collections.sort(list, (e1, e2) -> (int) (e2.getValue() - e1.getValue()));
return list.get(0);
}
private <K> Map.Entry<K, Double> worstEntry(Map<K, Double> map) {
List<Map.Entry<K, Double>> list = new ArrayList<>(map.entrySet());
Collections.sort(list, (e1, e2) -> (int) (e1.getValue() - e2.getValue()));
return list.get(0);
}
private Map<Move, Double> bestMoves() {
Map<Move, Double> moves = new HashMap<>();
state.possibleMoves().stream().parallel().forEach(move -> {
if (!Thread.currentThread().isInterrupted()) {
Game newState = state.playMove(move);
Double score = newState.isTerminal() ? newState.utility()
: worstEntry(new (newState).worstMoves()).getValue();
moves.put(move, score);
}
});
return moves;
}
private Map<Move, Double> worstMoves() {
Map<Move, Double> moves = new HashMap<>();
state.possibleMoves().stream().parallel().forEach(move -> {
if (!Thread.currentThread().isInterrupted()) {
Game newState = state.playMove(move);
Double score = newState.isTerminal() ? -newState.utility()
: bestEntry(new (newState).bestMoves()).getValue();
moves.put(move, score);
}
});
return moves;
}
ps: I also tried without "parallel()" but again there is still a single thread left running.
Thanks in advance.
Thank you all for your answers. I think I found a simpler solution.
First of all , I think the reason that future.cancel(true) didn't work is because it probably only set the interrupted flag on the thread that started the task. (that is, the thread that is associated with the future).
However because the task itself uses parallel stream processing, it spawns workers on different threads which are never get interrupted, and therefore I cannot periodically check the isInterrupted() flag.
The "solution" (or maybe more of work-around) that I found is to keep my own interrupted flag in my algorithm's objects, and manually set it to true when the task is cancelled. Because all threads work on the same instanced they all have access to the interrupted flag and they obey.
Future.cancel just set the thread as interrupted, then your code must treat it as follow:
public static void main(String[] args) throws InterruptedException {
final ExecutorService executor = Executors.newSingleThreadExecutor();
final Future<Integer> future = executor.submit(() -> count());
try {
System.out.println(future.get(1, TimeUnit.SECONDS));
} catch (Exception e){
future.cancel(true);
e.printStackTrace();
}finally {
System.out.printf("status=finally, cancelled=%s, done=%s%n", future.isCancelled(), future.isDone());
executor.shutdown();
}
}
static int count() throws InterruptedException {
while (!Thread.interrupted());
throw new InterruptedException();
}
As you can see the count keep checking if the thread is available to keep running, you have to understand that actually there is not guarantee that a running Thread can be stopped if she don't want to.
Reference:
Why set the interrupt bit in a Callable
how to suspend thread using thread's id?
UPDATE 2017-11-18 23:22
I wrote a FutureTask extension that have the ability to try to stop the Thread even if the code doesn't respect the interrupt signal. Keep in mind that it is unsafe because the Thread.stop method is deprecated, anyway it is working and if you really need that you can use it (Please read Thread.stop deprecation notes before, for example, if you are using locks, then run .stop can cause deadlocks).
Test code
public static void main(String[] args) throws InterruptedException {
final ExecutorService executor = newFixedSizeExecutor(1);
final Future<Integer> future = executor.submit(() -> count());
try {
System.out.println(future.get(1, TimeUnit.SECONDS));
} catch (Exception e){
future.cancel(true);
e.printStackTrace();
}
System.out.printf("status=finally, cancelled=%s, done=%s%n", future.isCancelled(), future.isDone());
executor.shutdown();
}
static int count() throws InterruptedException {
while (true);
}
Custom Executor
static ThreadPoolExecutor newFixedSizeExecutor(final int threads) {
return new ThreadPoolExecutor(threads, threads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>()){
protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) {
return new StoppableFutureTask<>(new FutureTask<>(callable));
}
};
}
static class StoppableFutureTask<T> implements RunnableFuture<T> {
private final FutureTask<T> future;
private Field runnerField;
public StoppableFutureTask(FutureTask<T> future) {
this.future = future;
try {
final Class clazz = future.getClass();
runnerField = clazz.getDeclaredField("runner");
runnerField.setAccessible(true);
} catch (Exception e) {
throw new Error(e);
}
}
#Override
public boolean cancel(boolean mayInterruptIfRunning) {
final boolean cancelled = future.cancel(mayInterruptIfRunning);
if(cancelled){
try {
((Thread) runnerField.get(future)).stop();
} catch (Exception e) {
throw new Error(e);
}
}
return cancelled;
}
#Override
public boolean isCancelled() {
return future.isCancelled();
}
#Override
public boolean isDone() {
return future.isDone();
}
#Override
public T get() throws InterruptedException, ExecutionException {
return future.get();
}
#Override
public T get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
return future.get(timeout, unit);
}
#Override
public void run() {
future.run();
}
}
output
java.util.concurrent.TimeoutException
at java.util.concurrent.FutureTask.get(FutureTask.java:205)
at com.mageddo.spark.sparkstream_1.Main$StoppableFutureTask.get(Main.java:91)
at com.mageddo.spark.sparkstream_1.Main.main(Main.java:20)
status=finally, cancelled=true, done=true
Process finished with exit code 0
I am investigating Java 8 CompletableFutures and read (and seen) that I should employ thenCompose instead of thenApply.
I have converted my code to use thenCompose but I have a feeling in an incorrect manner.
Here is my controlling code...
final CompletableFuture<List<String>> extractor = get(htmlPageSource);
#SuppressWarnings("unchecked")
final CompletableFuture<List<Documentable>>[] completableFutures =
new CompletableFuture[ENDPOINT.EXTRACTABLES.size()];
int index = 0;
for( ENDPOINT endpoint : ENDPOINT.EXTRACTABLES ) {
final CompletableFuture<List<Documentable>> metaData =
extractor.thenComposeAsync(
s -> endpoint.contactEndpoit(s), executorService );
completableFutures[index++] = metaData.exceptionally(x -> failedList(x));
}
CompletableFuture
.allOf( completableFutures )
.thenComposeAsync( dummy -> combineDocuments( completableFutures ))
.thenAccept ( x -> finish( x ))
.exceptionally( x -> failed( x ));
private List<Documentable> failedList(final Throwable x) {
LOGGER.error("failedList", x);
final List<Documentable> metaData = new ArrayList<>();
return metaData;
}
private Void failed(final Throwable x) {
LOGGER.error("failed", x);
return null;
}
Which I believe is acceptable
However the code that makes me uneasy is this:-
WWW_SITE_ONE("https://example.site.one/") {
#Override
public <T extends Documentable> CompletionStage<List<T>> contactEndpoit( final List<String> elements) {
LOGGER.info("WWW_SITE_ONE " + Thread.currentThread().getName());
final List<T> SITE_ONEs = new ArrayList<>();
for (final String element : elements) {
try {
final String json = Jsoup.connect(ENDPOINT.WWW_SITE_ONE.getBaseUrl() + element).ignoreContentType(true).ignoreHttpErrors(true).maxBodySize(0).timeout(60000).execute().body();
if (json.contains("errors")) {
continue;
}
final T SITE_ONE = OBJECT_READER_SITE_ONE.readValue(json);
SITE_ONEs.add(SITE_ONE);
}
catch( final Throwable e ) {
LOGGER.error("WWW_SITE_ONE failed", e);
throw new RuntimeException(e);
}
}
return CompletableFuture.supplyAsync(() -> SITE_ONEs);
}
},
WWW_SITE_TWO("https://example.site.two/") {
#Override
public <T extends Documentable> CompletionStage<List<T>> contactEndpoit(final List<String> elements) {
LOGGER.info("WWW_SITE_TWO " + Thread.currentThread().getName());
final List<T> SITE_TWOs = new ArrayList<>();
for (final String element : elements) {
try {
final String json = Jsoup.connect(ENDPOINT.WWW_SITE_TWO.getBaseUrl() + element).ignoreContentType(true).ignoreHttpErrors(true).maxBodySize(0).timeout(60000).execute().body();
if (json.equals("Resource not found.")) {
continue;
}
final T SITE_TWO = OBJECT_READER_SITE_TWO.readValue(json);
SITE_TWOs.add(SITE_TWO);
}
catch (final Throwable e) {
LOGGER.error("WWW_SITE_TWO failed", e);
throw new RuntimeException(e);
}
}
return CompletableFuture.supplyAsync(() -> SITE_TWOs);
}
},
WWW_SITE_THREE("https://example.site.three/") {
#Override
public <T extends Documentable> CompletionStage<List<T>> contactEndpoit(final List<String> elements) {
LOGGER.info("WWW_SITE_THREE " + Thread.currentThread().getName());
final List<T> SITE_THREEs = new ArrayList<>();
for (final String element : elements) {
try {
final String SITE_THREEJsonString = Jsoup
.connect( ENDPOINT.WWW_SITE_THREE.getBaseUrl() + element)
.ignoreContentType(true)
.ignoreHttpErrors(true)
.maxBodySize(0)
.timeout(60000)
.execute()
.body();
final SITE_THREE SITE_THREE_Json = OBJECT_READER_SITE_THREE.readValue(SITE_THREEJsonString);
final T SITE_THREE = (T) SITE_THREE_Json;
if (SITE_THREE_Json.getHitCount() > 0) {
SITE_THREEs.add(SITE_THREE);
}
}
catch (final Throwable e) {
LOGGER.error("WWW_SITE_THREE failed", e);
throw new RuntimeException(e);
}
}
return CompletableFuture.supplyAsync(() -> SITE_THREEs);
}
};
Its where I am returning CompletableFuture.supplyAsync(() -> SITE_THREEs);
Is this the correct approach?
Or does this start another asynchronous thread to simply return my List<>?
As the name suggests, supplyAsync will perform an asynchronous operation, executing the Supplier’s get() method, hence the body of the lambda expression, in a background thread, regardless of how trivial it is. Since the implementation of supplyAsync has no way to check how trivial the code encapsulated by the Supplier is, it has to work this way.
Instead of CompletableFuture.supplyAsync(() -> SITE_THREEs), you should use CompletableFuture.completedFuture(SITE_THREEs) which returns a future that has already been completed with the result, hence, not requiring additional actions.
If the method only returns completed stages or throws an exception, you may also change it to return the result value instead of a CompletionStage and use thenApply instead of thenCompose, simplifying your code—unless you want to keep the option of introducing asynchronous operations in a future version of that method.
Java 8 introduces CompletableFuture, a new implementation of Future that is composable (includes a bunch of thenXxx methods). I'd like to use this exclusively, but many of the libraries I want to use return only non-composable Future instances.
Is there a way to wrap up a returned Future instances inside of a CompleteableFuture so that I can compose it?
If the library you want to use also offers a callback style method in addition to the Future style, you can provide it a handler that completes the CompletableFuture without any extra thread blocking. Like so:
AsynchronousFileChannel open = AsynchronousFileChannel.open(Paths.get("/some/file"));
// ...
CompletableFuture<ByteBuffer> completableFuture = new CompletableFuture<ByteBuffer>();
open.read(buffer, position, null, new CompletionHandler<Integer, Void>() {
#Override
public void completed(Integer result, Void attachment) {
completableFuture.complete(buffer);
}
#Override
public void failed(Throwable exc, Void attachment) {
completableFuture.completeExceptionally(exc);
}
});
completableFuture.thenApply(...)
Without the callback the only other way I see solving this is to use a polling loop that puts all your Future.isDone() checks on a single thread and then invoking complete whenever a Future is gettable.
There is a way, but you won't like it. The following method transforms a Future<T> into a CompletableFuture<T>:
public static <T> CompletableFuture<T> makeCompletableFuture(Future<T> future) {
if (future.isDone())
return transformDoneFuture(future);
return CompletableFuture.supplyAsync(() -> {
try {
if (!future.isDone())
awaitFutureIsDoneInForkJoinPool(future);
return future.get();
} catch (ExecutionException e) {
throw new RuntimeException(e);
} catch (InterruptedException e) {
// Normally, this should never happen inside ForkJoinPool
Thread.currentThread().interrupt();
// Add the following statement if the future doesn't have side effects
// future.cancel(true);
throw new RuntimeException(e);
}
});
}
private static <T> CompletableFuture<T> transformDoneFuture(Future<T> future) {
CompletableFuture<T> cf = new CompletableFuture<>();
T result;
try {
result = future.get();
} catch (Throwable ex) {
cf.completeExceptionally(ex);
return cf;
}
cf.complete(result);
return cf;
}
private static void awaitFutureIsDoneInForkJoinPool(Future<?> future)
throws InterruptedException {
ForkJoinPool.managedBlock(new ForkJoinPool.ManagedBlocker() {
#Override public boolean block() throws InterruptedException {
try {
future.get();
} catch (ExecutionException e) {
throw new RuntimeException(e);
}
return true;
}
#Override public boolean isReleasable() {
return future.isDone();
}
});
}
Obviously, the problem with this approach is, that for each Future, a thread will be blocked to wait for the result of the Future--contradicting the idea of futures. In some cases, it might be possible to do better. However, in general, there is no solution without actively wait for the result of the Future.
If your Future is the result of a call to an ExecutorService method (e.g. submit()), the easiest would be to use the CompletableFuture.runAsync(Runnable, Executor) method instead.
From
Runnbale myTask = ... ;
Future<?> future = myExecutor.submit(myTask);
to
Runnbale myTask = ... ;
CompletableFuture<?> future = CompletableFuture.runAsync(myTask, myExecutor);
The CompletableFuture is then created "natively".
EDIT: Pursuing comments by #SamMefford corrected by #MartinAndersson, if you want to pass a Callable, you need to call supplyAsync(), converting the Callable<T> into a Supplier<T>, e.g. with:
CompletableFuture.supplyAsync(() -> {
try { return myCallable.call(); }
catch (Exception ex) { throw new CompletionException(ex); } // Or return default value
}, myExecutor);
Because T Callable.call() throws Exception; throws an exception and T Supplier.get(); doesn't, you have to catch the exception so prototypes are compatible.
A note on exception handling
The get() method doesn't specify a throws, which means it should not throw a checked exception. However, unchecked exception can be used. The code in CompletableFuture shows that CompletionException is used and is unchecked (i.e. is a RuntimeException), hence the catch/throw wrapping any exception into a CompletionException.
Also, as #WeGa indicated, you can use the handle() method to deal with exceptions potentially being thrown by the result:
CompletableFuture<T> future = CompletableFuture.supplyAsync(...);
future.handle((ex,res) -> {
if (ex != null) {
// An exception occurred ...
} else {
// No exception was thrown, 'res' is valid and can be handled here
}
});
I published a little futurity project that tries to do better than the straightforward way in the answer.
The main idea is to use only one thread (and of course with not just a spin loop) to check all Futures states inside, which helps to avoid blocking a thread from a pool for each Future -> CompletableFuture transformation.
Usage example:
Future oldFuture = ...;
CompletableFuture profit = Futurity.shift(oldFuture);
Suggestion:
http://www.thedevpiece.com/converting-old-java-future-to-completablefuture/
But, basically:
public class CompletablePromiseContext {
private static final ScheduledExecutorService SERVICE = Executors.newSingleThreadScheduledExecutor();
public static void schedule(Runnable r) {
SERVICE.schedule(r, 1, TimeUnit.MILLISECONDS);
}
}
And, the CompletablePromise:
public class CompletablePromise<V> extends CompletableFuture<V> {
private Future<V> future;
public CompletablePromise(Future<V> future) {
this.future = future;
CompletablePromiseContext.schedule(this::tryToComplete);
}
private void tryToComplete() {
if (future.isDone()) {
try {
complete(future.get());
} catch (InterruptedException e) {
completeExceptionally(e);
} catch (ExecutionException e) {
completeExceptionally(e.getCause());
}
return;
}
if (future.isCancelled()) {
cancel(true);
return;
}
CompletablePromiseContext.schedule(this::tryToComplete);
}
}
Example:
public class Main {
public static void main(String[] args) {
final ExecutorService service = Executors.newSingleThreadExecutor();
final Future<String> stringFuture = service.submit(() -> "success");
final CompletableFuture<String> completableFuture = new CompletablePromise<>(stringFuture);
completableFuture.whenComplete((result, failure) -> {
System.out.println(result);
});
}
}
Let me suggest another (hopefully, better) option:
https://github.com/vsilaev/java-async-await/tree/master/com.farata.lang.async.examples/src/main/java/com/farata/concurrent
Briefly, the idea is the following:
Introduce CompletableTask<V> interface -- the union of the
CompletionStage<V> + RunnableFuture<V>
Warp ExecutorService to return CompletableTask from submit(...) methods (instead of Future<V>)
Done, we have runnable AND composable Futures.
Implementation uses an alternative CompletionStage implementation (pay attention, CompletionStage rather than CompletableFuture):
Usage:
J8ExecutorService exec = J8Executors.newCachedThreadPool();
CompletionStage<String> = exec
.submit( someCallableA )
.thenCombineAsync( exec.submit(someCallableB), (a, b) -> a + " " + b)
.thenCombine( exec.submit(someCallableC), (ab, b) -> ab + " " + c);
public static <T> CompletableFuture<T> fromFuture(Future<T> f) {
return CompletableFuture.completedFuture(null).thenCompose(avoid -> {
try {
return CompletableFuture.completedFuture(f.get());
} catch (InterruptedException e) {
return CompletableFuture.failedFuture(e);
} catch (ExecutionException e) {
return CompletableFuture.failedFuture(e.getCause());
}
});
}
The main idea goes like this:
Future<?> future = null;
return CompletableFuture.supplyAsync(future::get);
However, you will receive some warnings from your compiler.
So, here is the first option.
Future<?> future = null;
return CompletableFuture.supplyAsync(
()->{
try {
return future.get();
} catch (Exception e) {
throw new RuntimeException(e);
}
});
Second Option, hide the try...catch via casting the functional interface.
#FunctionalInterface
public interface MySupplier<T> extends Supplier<T> {
#Override
default T get() {
try {
return getInternal();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
T getInternal() throws Exception;
}
public static void main(String[] args) {
Future<?> future = null;
return CompletableFuture.supplyAsync((MySupplier<?>) future::get);
}
Third Option, find out some 3rd party lib which has provided such a functional interface.
See Also: Java 8 Lambda function that throws exception?
I have implemented multithreading in my service layer and want to ensure I have dealt with all cases where the threads are properly handled. I don't want to end up with some kind of exception (such as RuntimeEx or InterruptedEx) which could leave my app in a bad state.
My code is below. Let me know if you can see any errors. Recommendations are most welcome. I'm using java 6.
public class MyRunnable implements Runnable {
private List<MyData> list;
private Person p;
public MyRunnable(List<MyData> list, Person p) {
this.list = list; // this list is passed in and cannot be null
this.p = p;
}
#Override
public void run() {
// before calling any of the services that gets data from the
// database, check if the thread has been interrupted
if (Thread.interrupted()) return;
List<TypeA> aList;
try {
aList = getTypeAFromDatabase1(p);
} catch (Exception e) {
throw new RuntimeException(e);
}
if (Thread.interrupted()) return;
List<TypeB> bList;
try {
bList = getTypeBFromDatabase2(p);
} catch (Exception e) {
throw new RuntimeException(e);
}
if (Thread.interrupted()) return;
List<TypeC> cList;
try {
cList = getTypeCFromSomeWebService(p);
} catch (Exception e) {
throw new RuntimeException(e);
}
MyData d = new MyData();
d.setPerson(p);
d.setTypeA(aList);
d.setTypeB(bList);
d.setTypeC(cList);
list.add(d);
}
}
Service that uses Runnable:
#JsonOperation
public static List<MyData> getMyData(MyParams params) throws Exception {
List<Person> persons = params.getPersonList();
try {
// use synchronized list since all threads will add to this list
List<MyData> retList = Collections.synchronizedList(new ArrayList<MyData>());
List<Thread> threads = new ArrayList<Thread>();
// For each person, start a new thread. It there are any runtime
// exceptions thrown by any one thread, it will be caught by the
// bigger try catch block. In case of runtime exception, we will
// return back to the client right away but the other threads
// are still processing
try {
for (Person p : persons) {
// create a thread per person and start it
Runnable task = new MyRunnable(retList, p);
Thread worker = new Thread(task);
threads.add(worker);
worker.start();
// remember the thread for later use
threads.add(worker);
}
for (Thread thread : threads) {
// wait for all threads (by waiting on one thread at a time)
thread.join(3000); //3 seconds between checking on this thread
}
} catch (RuntimeException e) {
log.error(e);
for (Thread thread : threads) {
// try and send an interrupt to all threads so that they
// don't fetch any more data from the database
thread.interrupt();
}
throw e;
}
return retList;
} catch (Exception e) {
log.error(e);
throw e;
}
}
In most situations it is easier to use tasks instead of threads. You start with an ExecutorService, which restricts the number of threads and is shared across all service operations:
// inject with IoC framework
ExecutorService executor = Executors.newFixedThreadPool(10);
You use the method invokeAll to execute a task for each person. If the tasks do not finish within the given period, then the remaining tasks will be automatically cancelled. In this case, an exception is thrown when invoking the get method of the corresponding future. That means there is no need for additional exception handling.
public List<MyData> getMyData(MyParams params) throws Exception {
List<Callable<MyData>> tasks = new ArrayList<>();
for (Person p : persons) {
tasks.add(new Callable<MyData>() { // use Lambda in Java 8
public MyData call() {
MyData d = new MyData();
d.setPerson(p);
d.setTypeA(getTypeAFromDatabase1(p));
d.setTypeB(getTypeBFromDatabase2(p));
d.setTypeC(getTypeCFromSomeWebService(p));
return d;
}
});
}
List<MyData> result = new ArrayList<>();
for (Future<MyData> future : executor.invokeAll(tasks, 3000, TimeUnit.MILLISECONDS)) {
result.add(future.get());
}
return result;
}
There is no need to check the interrupted state within the callable. If a blocking operation is called within one of the methods, the method will automatically abort execution with an InterruptedException or some other exception (if it is implemented correctly). It is also possible to set the interrupted state instead of throwing an exception. However, that makes less sense for methods with return values.