I want to achieve what the following pseudo code illustrates:
int functionA() {
Future res;
// ...
setCallbackForSomething(new Callback() {
public void onCall() {
// ...
res = 5;
}
});
// ...
return doSomethingElse(res.get());
}
i.e. the functionA blocks until the callback has been called, then processes the result and returns something.
Is something like that possible with Future? The usual usage,
Future res = executor.submit(...);
...
res.get()
does not seem to work here. I also cannot change the fact that I have to set the callback like this.
Future has limited features. From the javadoc
A Future represents the result of an asynchronous computation. Methods
are provided to check if the computation is complete, to wait for its
completion, and to retrieve the result of the computation.
It only exposes read operations (except for cancel). You won't be able to achieve what you want with Future.
Instead, since Java 8, you can use CompletableFuture
A Future that may be explicitly completed (setting its value and
status), and may be used as a CompletionStage, supporting dependent
functions and actions that trigger upon its completion.
You initialize the CompletableFuture
CompletableFuture<Integer> res = new CompletableFuture<>();
and complete it either normally or exceptionally
setCallbackForSomething(new Callback() {
public void onCall() {
// ...
res.complete(5); // or handle exception
}
});
Instead of calling get, you can chain a completion task on the CompletableFuture to call doSomethingElse.
res.thenAccept(value -> doSomethingElse(value));
Though you can still call get if you want to, blocking until the future is completed.
Before Java 8, the Guava library provided SettableFuture to achieve the "set" part of a promised value. But it's also a ListenableFuture so you can chain other operations on completion.
Related
I need to perform some extra tasks but let the original thread finish up, e.g. send back an HTTP response.
I think I can just do this:
return mainTasksFuture.thenApply(response -> {
CompletableFuture.runAsync(() -> {
// extra tasks
});
return response;
});
But I remembered there's a thenRunAsync. Is
return mainTasksFuture.thenApply(response -> {
return response;
}).thenRunAsync(() -> {
// extra tasks
});
basically another way to do the same thing? In other words, are the then*Async methods terminators (completion methods) that return the previous chain's result in the original thread, then spawn a new thread to execute the rest?
I'm almost certain the answer is no. It just seems it might be that purely based on method names, to someone new to CompletableFutures. I wanted a confirmation though, in case what I'm reading about ForkJoinPool.commonPool is actually saying what I'm doubting, just in a different way.
You wrote
It just ∗seems* it might be that purely based on method names, to someone new to CompletableFutures.
Well, the method names correctly reflect what the methods do. Both, runAsync and thenRunAsync initiate the asynchronous execution of a Runnable and return a future, which will be completed when the asynchronous execution has finished. So the similarity in the names is justified.
It’s your code which is fundamentally different.
In this variant
return mainTasksFuture.thenApply(response -> {
CompletableFuture.runAsync(() -> {
// extra tasks
});
return response;
});
you are ignoring the future returned by runAsync entirely, so the future returned by thenApply will be completed as soon as the asynchronous operation has been triggered. The caller can retrieve the result value while the “extra tasks” are still running concurrently.
In contrast, with
return mainTasksFuture.thenApply(response -> {
return response;
}).thenRunAsync(() -> {
// extra tasks
});
the thenApply is entirely obsolete as it doesn’t do anything. But you are returning the future returned by thenRunAsync, which will be completed when the asynchronous execution of the Runnable has finished and has the type CompletableFuture<Void>, as the runnable does not produce a value (the future will be completed with null). In the exceptional case, it would get completed with the exception of mainTasksFuture, but in the successful case, it does not pass through the result value.
If the first variant matches your actual intention (the caller should not depend on the completion of the extra tasks), simply don’t model them as a dependency:
mainTasksFuture.thenRunAsync(() -> {
// extra tasks
});
return mainTasksFuture; // does not depend on the completion of extra task
Otherwise, stay with variant 2 (minus obsolete things)
return mainTasksFuture.thenRunAsync(() -> {
// extra tasks
}); // depends on the completion of extra task but results in (Void)null
if you don’t need the result value. Otherwise, you can use
return mainTasksFuture.thenApplyAsync(response -> {
// extra tasks
return response;
}); // depends on the completion of extra task and returns original result
it would be the same as with
return mainTasksFuture.thenCompose(response ->
CompletableFuture.runAsync(() -> {
// extra tasks
}).thenApply(_void -> response));
which does not ignore the future returned by runAsync, but there’s no advantage in this complication, compared to thenApplyAsync.
Another alternative would be
return mainTasksFuture.whenComplete((response,failure) -> {
if(failure == null) {
// extra tasks
}
});
as the future returned by whenComplete will get completed with the original future’s result when the extra tasks have been completed. But the function is always evaluated, even when the original future completed exceptionally, so it needs another conditional if that’s not desired.
Both runAsync and thenRunAsync execute the Runnable taks asynchronous
executes the given action using this stage's default asynchronous execution facility
Question : In other words, are the then*Async methods terminators (completion methods) that return the previous chain's result in the original thread, then spawn a new thread to execute the rest?
Answer: No, From documentation One stage's execution may be triggered by completion of a single stage, or both of two stages, or either of two stages.So basically the result might be returned based on how programmer coded that part, but now in your case (using thenRunAsync) the result will be returned after first stage completion because in the second stage thenRunAsync you are taking result from first stage as input but not returning anything.
Interface CompletionStage
One stage's execution may be triggered by completion of a single stage, or both of two stages, or either of two stages. Dependencies on a single stage are arranged using methods with prefix then. Those triggered by completion of both of two stages may combine their results or effects, using correspondingly named methods. Those triggered by either of two stages make no guarantees about which of the results or effects are used for the dependent stage's computation.
There is also a slight difference between first example and second example
Example : 1 In this example the Runnable tasks get executed asynchronously before returning the result, both Function from thenApply and Runnable from runAsync will be executed concurrently
return mainTasksFuture.thenApply(response -> {
CompletableFuture.runAsync(() -> {
// extra tasks
});
return response;
});
Example : 2 In this example Runnable task from thenRunAsync will be executed after completion of Function from thenApply
return mainTasksFuture.thenApply(response -> {
return response;
}).thenRunAsync(() -> {
// extra tasks
});
Are there any advantages of processing result using a ListenableFuture when submitting a tasks to ExecutorService instead of doing it the plain old java way by simply calling a function that processes the results?
Future:
Future<ScanResult> result = threadPoolExecutor.submit(
new Callable<ScanResult>() {
//long running process to get scanResult
return scanResult;
});
ScanResult sr = result.get();
OR use guava ListenableFuture to prevent manually get() calling.
Plain Java Way:
threadPoolExecutor.submit(new Callable<Void>() {
#Override
public Void call() throws Exception {
//long running process to get scanResult
jobCompleted(scanResult);
return null;
}
});
I have not worked on Guava Concurrency or ListenableFuture but I think the main advantage is generic event based program design which is easier to understand and visualize than manually triggering code based on events.
Future.get() is a blocking method so you are anyhow blocked till Callable is complete so you are coupling two independent code execution paths into a single execution path. Adding listener decouples them and couples them logically based on event.
Also as per github link, it is strongly advised to use it and I guess reason for it might be additional services supported by ListenableFuture that might not be present in plain Future.
Hope it helps !!
I've got a question about CompletableFuture and its possible usage for lazy computations.
It seems like it is a great substitute for RunnableFuture for this task since it is possible to easily create task chains and to have total control of each chain link. Still I found that it is very hard to control when exactly does the computation take place.
If I just create a CompletableFuture with supplyAssync method or something like that, it is OK. It waits patiently for me to call get or join method to compute. But if I try to make an actual chain with whenCompose, handle or any other method, the evaluation starts immediately, which is very frustrating.
Of course, I can always place some blocker task at the start of the chain and release the block when I am ready to begin calculation, but it seems a bit ugly solution. Does anybody know how to control when does CompletableFuture actually run.
CompletableFuture is a push-design, i.e. results are pushed down to dependent tasks as soon as they become available. This also means side-chains that are not in themselves consumed still get executed, which can have side-effects.
What you want is a pull-design where ancestors would only be pulled in as their data is consumed.
This would be a fundamentally different design because side-effects of non-consumed trees would never happen.
Of course with enough contortions CF could be made to do what you want, but you should look into the fork-join framework instead which allows you to only run the computations you depend on instead of pushing down results.
There's a conceptual difference between RunnableFuture and CompletableFuture that you're missing here.
RunnableFuture implementations take a task as input and hold onto it. It runs the task when you call the run method.
A CompletableFuture does not hold onto a task. It only knows about the result of a task. It has three states: complete, incomplete, and completed exceptionally (failed).
CompletableFuture.supplyAsync is a factory method that gives you an incomplete CompletableFuture. It also schedules a task which, when it completes, will pass its result to the CompletableFuture's complete method. In other words, the future that supplyAsync hands you doesn't know anything about the task, and can't control when the task runs.
To use a CompletableFuture in the way you describe, you would need to create a subclass:
public class RunnableCompletableFuture<T> extends CompletableFuture<T> implements RunnableFuture<T> {
private final Callable<T> task;
public RunnableCompletableFuture(Callable<T> task) {
this.task = task;
}
#Override
public void run() {
try {
complete(task.call());
} catch (Exception e) {
completeExceptionally(e);
}
}
}
A simple way of dealing with your problem is wrapping your CompletableFuture in something with a lazy nature. You could use a Supplier or even Java 8 Stream.
it is late, but how about using constructor for first CompletableFuture in the chain?
CompletableFuture<Object> cf = new CompletableFuture<>();
// compose the chain
cf.thenCompose(sometask_here);
// later starts the chain with
cf.complete(anInputObject);
I am playing with Java 8 completable futures. I have the following code:
CountDownLatch waitLatch = new CountDownLatch(1);
CompletableFuture<?> future = CompletableFuture.runAsync(() -> {
try {
System.out.println("Wait");
waitLatch.await(); //cancel should interrupt
System.out.println("Done");
} catch (InterruptedException e) {
System.out.println("Interrupted");
throw new RuntimeException(e);
}
});
sleep(10); //give it some time to start (ugly, but works)
future.cancel(true);
System.out.println("Cancel called");
assertTrue(future.isCancelled());
assertTrue(future.isDone());
sleep(100); //give it some time to finish
Using runAsync I schedule execution of a code that waits on a latch. Next I cancel the future, expecting an interrupted exception to be thrown inside. But it seems that the thread remains blocked on the await call and the InterruptedException is never thrown even though the future is canceled (assertions pass). An equivalent code using ExecutorService works as expected. Is it a bug in the CompletableFuture or in my example?
When you call CompletableFuture#cancel, you only stop the downstream part of the chain. Upstream part, i. e. something that will eventually call complete(...) or completeExceptionally(...), doesn't get any signal that the result is no more needed.
What are those 'upstream' and 'downstream' things?
Let's consider the following code:
CompletableFuture
.supplyAsync(() -> "hello") //1
.thenApply(s -> s + " world!") //2
.thenAccept(s -> System.out.println(s)); //3
Here, the data flows from top to bottom - from being created by supplier, through being modified by function, to being consumed by println. The part above particular step is called upstream, and the part below is downstream. E. g. steps 1 and 2 are upstream for step 3.
Here's what happens behind the scenes. This is not precise, rather it's a convenient mind model of what's going on.
Supplier (step 1) is being executed (inside the JVM's common ForkJoinPool).
The result of the supplier is then being passed by complete(...) to the next CompletableFuture downstream.
Upon receiving the result, that CompletableFuture invokes next step - a function (step 2) which takes in previous step result and returns something that will be passed further, to the downstream CompletableFuture's complete(...).
Upon receiving the step 2 result, step 3 CompletableFuture invokes the consumer, System.out.println(s). After consumer is finished, the downstream CompletableFuture will receive it's value, (Void) null
As we can see, each CompletableFuture in this chain has to know who are there downstream waiting for the value to be passed to their's complete(...) (or completeExceptionally(...)). But the CompletableFuture don't have to know anything about it's upstream (or upstreams - there might be several).
Thus, calling cancel() upon step 3 doesn't abort steps 1 and 2, because there's no link from step 3 to step 2.
It is supposed that if you're using CompletableFuture then your steps are small enough so that there's no harm if a couple of extra steps will get executed.
If you want cancellation to be propagated upstream, you have two options:
Implement this yourself - create a dedicated CompletableFuture (name it like cancelled) which is checked after every step (something like step.applyToEither(cancelled, Function.identity()))
Use reactive stack like RxJava 2, ProjectReactor/Flux or Akka Streams
Apparently, it's intentional. The Javadoc for the method CompletableFuture::cancel states:
[Parameters:] mayInterruptIfRunning - this value has no effect in this implementation because interrupts are not used to control processing.
Interestingly, the method ForkJoinTask::cancel uses almost the same wording for the parameter mayInterruptIfRunning.
I have a guess on this issue:
interruption is intended to be used with blocking operations, like sleep, wait or I/O operations,
but neither CompletableFuture nor ForkJoinTask are intended to be used with blocking operations.
Instead of blocking, a CompletableFuture should create a new CompletionStage, and cpu-bound tasks are a prerequisite for the fork-join model. So, using interruption with either of them would defeat their purpose. And on the other hand, it might increase complexity, that's not required if used as intended.
If you actually want to be able to cancel a task, then you have to use Future itself (e.g. as returned by ExecutorService.submit(Callable<T>), not CompletableFuture. As pointed out in the answer by nosid, CompletableFuture completely ignores any call to cancel(true).
My suspicion is that the JDK team did not implement interruption because:
Interruption was always hacky, difficult for people to understand, and difficult to work with. The Java I/O system is not even interruptible, despite calls to InputStream.read() being blocking calls! (And the JDK team have no plans to make the standard I/O system interruptible again, like it was in the very early Java days.)
The JDK team have been trying very hard to phase out old broken APIs from the early Java days, such as Object.finalize(), Object.wait(), Thread.stop(), etc. I believe Thread.interrupt() is considered to be in the category of things that must be eventually deprecated and replaced. Therefore, newer APIs (like ForkJoinPool and CompletableFuture) are already not supporting it.
CompletableFuture was designed for building DAG-structured pipelines of operations, similar to the Java Stream API. It's very dificult to succinctly describe how interruption of one node of a dataflow DAG should affect execution in the rest of the DAG. (Should all concurrent tasks be canceled immediately, when any node is interrupted?)
I suspect the JDK team just didn't want to deal with getting interruption right, given the levels of internal complexity that the JDK and libraries have reached these days. (The internals of the lambda system -- ugh.)
One very hacky way around this would be to have each CompletableFuture export a reference to itself to an externally-visible AtomicReference, then the Thread reference could be interrupted directly when needed from another external thread. Or if you start all the tasks using your own ExecutorService, in your own ThreadPool, you can manually interrupt any or all the threads that were started, even if CompletableFuture refuses to trigger interruption via cancel(true). (Note though that CompletableFuture lambdas cannot throw checked exceptions, so if you have an interruptible wait in a CompletableFuture, you'll have to re-throw as an unchecked exception.)
More simply, you could just declare an AtomicReference<Boolean> cancel = new AtomicReference<>() in an external scope, and periodically check this flag from inside each CompletableFuture task's lambda.
You could also try setting up a DAG of Future instances rather than a DAG of CompletableFuture instances, that way you can exactly specify how exceptions and interruption/cancellation in any one task should affect the other currently-running tasks. I show how to do this in my example code in my question here, and it works well, but it's a lot of boilerplate.
You need an alternative implementation of CompletionStage to accomplish true thread interruption. I've just released a small library that serves exactly this purpose - https://github.com/vsilaev/tascalate-concurrent
The call to wait will still block even if Future.cancel(..) is called. As mentioned by others the CompletableFuture will not use interrupts to cancel the task.
According to the javadoc of CompletableFuture.cancel(..):
mayInterruptIfRunning this value has no effect in this implementation because interrupts are not used to control processing.
Even if the implementation would cause an interrupt, you would still need a blocking operation in order to cancel the task or check the status via Thread.interrupted().
Instead of interrupting the Thread, which might not be always easy to do, you may have check points in your operation where you can gracefully terminate the current task. This can be done in a loop over some elements that will be processed or you check before each step of the operation for the cancel status and throw an CancellationException yourself.
The tricky part is to get a reference of the CompletableFuture within the task in order to call Future.isCancelled(). Here is an example of how it can be done:
public abstract class CancelableTask<T> {
private CompletableFuture<T> task;
private T run() {
try {
return compute();
} catch (Throwable e) {
task.completeExceptionally(e);
}
return null;
}
protected abstract T compute() throws Exception;
protected boolean isCancelled() {
Future<T> future = task;
return future != null && future.isCancelled();
}
public Future<T> start() {
synchronized (this) {
if (task != null) throw new IllegalStateException("Task already started.");
task = new CompletableFuture<>();
}
return task.completeAsync(this::run);
}
}
Edit: Here the improved CancelableTask version as a static factory:
public static <T> CompletableFuture<T> supplyAsync(Function<Future<T>, T> operation) {
CompletableFuture<T> future = new CompletableFuture<>();
return future.completeAsync(() -> operation.apply(future));
}
here is the test method:
#Test
void testFuture() throws InterruptedException {
CountDownLatch started = new CountDownLatch(1);
CountDownLatch done = new CountDownLatch(1);
AtomicInteger counter = new AtomicInteger();
Future<Object> future = supplyAsync(task -> {
started.countDown();
while (!task.isCancelled()) {
System.out.println("Count: " + counter.getAndIncrement());
}
System.out.println("Task cancelled");
done.countDown();
return null;
});
// wait until the task is started
assertTrue(started.await(5, TimeUnit.SECONDS));
future.cancel(true);
System.out.println("Cancel called");
assertTrue(future.isCancelled());
assertTrue(future.isDone());
assertTrue(done.await(5, TimeUnit.SECONDS));
}
If you really want to use interrupts in addition to the CompletableFuture, then you can pass a custom Executor to CompletableFuture.completeAsync(..) where you create your own Thread, override cancel(..) in the CompletableFuture and interrupt your Thread.
The CancellationException is part of the internal ForkJoin cancel routine. The exception will come out when you retrieve the result of future:
try { future.get(); }
catch (Exception e){
System.out.println(e.toString());
}
Took a while to see this in a debugger. The JavaDoc is not that clear on what is happening or what you should expect.
What's the difference between Future and Promise?
They both act like a placeholder for future results, but where is the main difference?
(I'm not completely happy with the answers so far, so here is my attempt...)
I think that Kevin Wright's comment
You can make a Promise and it's up to you to keep it. When someone else makes you a promise you must wait to see if they honour it in the Future
summarizes it pretty well, but some explanation can be useful.
Futures and promises are pretty similar concepts, the difference is that a future is a read-only container for a result that does not yet exist, while a promise can be written (normally only once). The Java 8 CompletableFuture and the Guava SettableFuture can be thought of as promises, because their value can be set ("completed"), but they also implement the Future interface, therefore there is no difference for the client.
The result of the future will be set by "someone else" - by the result of an asynchronous computation. Note how FutureTask - a classic future - must be initialized with a Callable or Runnable, there is no no-argument constructor, and both Future and FutureTask are read-only from the outside (the set methods of FutureTask are protected). The value will be set to the result of the computation from the inside.
On the other hand, the result of a promise can be set by "you" (or in fact by anybody) anytime because it has a public setter method. Both CompletableFuture and SettableFuture can be created without any task, and their value can be set at any time. You send a promise to the client code, and fulfill it later as you wish.
Note that CompletableFuture is not a "pure" promise, it can be initialized with a task just like FutureTask, and its most useful feature is the unrelated chaining of processing steps.
Also note that a promise does not have to be a subtype of future and it does not have to be the same object. In Scala a Future object is created by an asynchronous computation or by a different Promise object. In C++ the situation is similar: the promise object is used by the producer and the future object by the consumer. The advantage of this separation is that the client cannot set the value of the future.
Both Spring and EJB 3.1 have an AsyncResult class, which is similar to the Scala/C++ promises. AsyncResult does implement Future but this is not the real future: asynchronous methods in Spring/EJB return a different, read-only Future object through some background magic, and this second "real" future can be used by the client to access the result.
According to this discussion, Promise has finally been called CompletableFuture for inclusion in Java 8, and its javadoc explains:
A Future that may be explicitly completed (setting its value and status), and may be used as a CompletionStage, supporting dependent functions and actions that trigger upon its completion.
An example is also given on the list:
f.then((s -> aStringFunction(s)).thenAsync(s -> ...);
Note that the final API is slightly different but allows similar asynchronous execution:
CompletableFuture<String> f = ...;
f.thenApply(this::modifyString).thenAccept(System.out::println);
I am aware that there's already an accepted answer but would like to add my two cents nevertheless:
TLDR: Future and Promise are the two sides of an asynchronous operation: consumer/caller vs. producer/implementor.
As a caller of an asynchronous API method, you will get a Future as a handle to the computation's result. You can e.g. call get() on it to wait for the computation to complete and retrieve the result.
Now think of how this API method is actually implemented: The implementor must return a Future immediately. They are responsible for completing that future as soon as the computation is done (which they will know because it is implementing the dispatch logic ;-)). They will use a Promise/CompletableFuture to do just that: Construct and return the CompletableFuture immediately, and call complete(T result) once the computation is done.
I will give an example of what is Promise and how its value could be set at any time, in opposite to Future, which value is only readable.
Suppose you have a mom and you ask her for money.
// Now , you trick your mom into creating you a promise of eventual
// donation, she gives you that promise object, but she is not really
// in rush to fulfill it yet:
Supplier<Integer> momsPurse = ()-> {
try {
Thread.sleep(1000);//mom is busy
} catch (InterruptedException e) {
;
}
return 100;
};
ExecutorService ex = Executors.newFixedThreadPool(10);
CompletableFuture<Integer> promise =
CompletableFuture.supplyAsync(momsPurse, ex);
// You are happy, you run to thank you your mom:
promise.thenAccept(u->System.out.println("Thank you mom for $" + u ));
// But your father interferes and generally aborts mom's plans and
// completes the promise (sets its value!) with far lesser contribution,
// as fathers do, very resolutely, while mom is slowly opening her purse
// (remember the Thread.sleep(...)) :
promise.complete(10);
Output of that is:
Thank you mom for $10
Mom's promise was created , but waited for some "completion" event.
CompletableFuture<Integer> promise...
You created such event, accepting her promise and announcing your plans to thank your mom:
promise.thenAccept...
At this moment mom started open her purse...but very slow...
and father interfered much faster and completed the promise instead of your mom:
promise.complete(10);
Have you noticed an executor that I wrote explicitly?
Interestingly, if you use a default implicit executor instead (commonPool) and father is not at home, but only mom with her "slow purse", then her promise will only complete, if the program lives longer than mom needs to get money from the purse.
The default executor acts kind of like a "daemon" and does not wait for all promises to be fulfilled. I have not found a good description of this fact...
Not sure if this can be an answer but as I see what others have said for someone it may look like you need two separate abstractions for both of these concepts so that one of them (Future) is just a read-only view of the other (Promise) ... but actually this is not needed.
For example take a look at how promises are defined in javascript:
https://promisesaplus.com/
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise
The focus is on the composability using the then method like:
asyncOp1()
.then(function(op1Result){
// do something
return asyncOp2();
})
.then(function(op2Result){
// do something more
return asyncOp3();
})
.then(function(op3Result){
// do something even more
return syncOp4(op3Result);
})
...
.then(function(result){
console.log(result);
})
.catch(function(error){
console.log(error);
})
which makes asynchronous computation to look like synchronous:
try {
op1Result = syncOp1();
// do something
op1Result = syncOp2();
// do something more
op3Result = syncOp3();
// do something even more
syncOp4(op3Result);
...
console.log(result);
} catch(error) {
console.log(error);
}
which is pretty cool.
(Not as cool as async-await but async-await just removes the boilerplate ....then(function(result) {.... from it).
And actually their abstraction is pretty good as the promise constructor
new Promise( function(resolve, reject) { /* do it */ } );
allows you to provide two callbacks which can be used to either complete the Promise successfully or with an error. So that only the code that constructs the Promise can complete it and the code that receives an already constructed Promise object has the read-only view.
With inheritance the above can be achieved if resolve and reject are protected methods.
For client code, Promise is for observing or attaching callback when a result is available, whereas Future is to wait for result and then continue. Theoretically anything which is possible to do with futures what can done with promises, but due to the style difference, the resultant API for promises in different languages make chaining easier.
Future vs Promise
Future and Promise are proxy object for unknown result
Promise completes a Future
Promise - write/producer of unknown result.
Future - read/consumer of unknown result. It has next states: pending, fulfilled, canceled
//Future has a reference to Promise
Future -> Promise
As a producer I promise something and responsible for it
As a consumer who retrieved a promise I expect to have a result in future. In future I can use the promise or reject it
As for Java CompletableFutures it is a Promise because you can set the result and also it implements Future
No set method in Future interface, only get method, so it is read-only.
About CompletableFuture, this article maybe helpful.
completablefuture
In this example you can take a look at how Promises can be used in Java
for creating asynchronous sequences of calls:
doSomeProcess()
.whenResult(result -> System.out.println(String.format("Result of some process is '%s'", result)))
.whenException(e -> System.out.println(String.format("Exception after some process is '%s'", e.getMessage())))
.map(String::toLowerCase)
.mapEx((result, e) -> e == null ? String.format("The mapped result is '%s'", result) : e.getMessage())
.whenResult(s -> System.out.println(s));