CompletableFuture

Remi Forax forax at univ-mlv.fr
Thu Nov 29 06:53:17 PST 2012


On 11/29/2012 01:22 PM, Doug Lea wrote:
> On 11/28/12 15:34, Doug Lea wrote:
>
>> Here's how to make trees/dags:
>>
>>    t1 = new CompletableFuture();
>>    t2 = t1.then(fun1);
>>    t3 = t1.then(fun2);
>>    t4 = t2.then(fun3);
>>    t5 = new CompletableFuture();
>>    t6 = t1.and(t3, fun4);
>
> (typo; should be t6 = t5.and(t3, fun4);
>>
>> This gives you (hoping the ascii-arg makes it through):
>>
>>
>>     / -> t2 -> t4
>> t1
>>     \ -> t3
>>           \
>> t5 -----> & t6
>>
>> Does that help?
>>
>
> Also, here's an update that contains a start on fleshing out some
> of the mechanics and intent, and adds a few things based on
> my own mangling of some suggestions by Chris Poviik (Google).
>
>
> /*
>  * Written by Doug Lea with assistance from members of JCP JSR-166
>  * Expert Group and released to the public domain, as explained at
>  * http://creativecommons.org/publicdomain/zero/1.0/
>  */
>
> import java.util.concurrent.Future;
> import java.util.concurrent.TimeUnit;
> import java.util.concurrent.ExecutionException;
> import java.util.concurrent.TimeoutException;
>
> /**
>  * A {@link Future} that may be explicitly completed (thus setting its
>  * value and status), and may support dependent CompletableFutures
>  * that trigger upon its completion.
>  *
>  * <p>Functions and actions supplied for dependent completions using
>  * {@code then}, {@code and}, {@code or}, and {@code exceptionally}
>  * are performed by the thread that completes the current
>  * CompletableFuture, or by the caller of the method, if already
>  * complete.
>  *
>  * <p> When two or more threads attempt to {@link #complete} or {@link
>  * #completeExceptionally} a CompletableFuture, only one of them will
>  * succeed. When completion entails computation of a function (or void
>  * action), the function is executed <em>after</em> establishing
>  * precedence. If this function terminates abruptly with an exception,
>  * then method {@code complete} acts as {@code completeExceptionally}
>  * with that exception. Method {@link #isCompleting} can be used to
>  * determine if a completion function gets "stuck", and method {@link
>  * #force} can be used in attempts to recover.
>  *
>  * <p>This class itself does not provide explicit support for
>  * asynchronous execution, but can be used in conjunction with several
>  * forms of concurrency. For examples, a new CompletableFuture may be
>  * constructed with (a function of) the results of an asynchronous
>  * task. Also, a supplied dependent action may itself fork a new task.
>  *
>  */
> public class CompletableFuture<T> implements Future<T> {
>
>     /**
>      * Creates a new incomplete CompletableFuture.
>      */
>     public CompletableFuture();
>
>     /**
>      * Creates a new CompletableFuture that is completed with the
>      * result of the given Future, if/when it completes.
>      */
>     public CompletableFuture(Future<T> f);

should be CompletableFuture(Future<? extends T> f) because Future as no 
set method.

>
>     /**
>      * Creates a new CompletableFuture that is completed with the
>      * result of applying the given function to the result of the
>      * given Future, if/when it completes.
>      */
>     public <U> CompletableFuture(Future<U> f, Function<? super U, T> fn);

again Future<? extends U>.

>
>     /**
>      * If not already completed, sets the value returned by get() and
>      * related methods to the given value.
>      *
>      * @return true if this invocation of {@code complete} caused
>      * this CompletableFuture to transition to a completed state,
>      * else false.
>      */
>     public boolean complete(T value);
>
>     /**
>      * If not already completed, causes invocations of get() to
>      * throw the given exception.
>      *
>      * @return true if this invocation of {@code
>      * completeExceptionally} caused this CompletableFuture to
>      * transition to a completed state, else false.
>      */
>     public boolean completeExceptionally(Throwable ex);
>
>     // Cascading functional completions
>
>     /**
>      * Creates and returns a CompletableFuture that is completed with
>      * the result of the given function of this CompletableFuture's
>      * result if/when this completes normally.
>      *
>      * @return the new CompletableFuture
>      */
>     public <U> CompletableFuture<U> then(Function<? super T,? extends 
> U> fn);
>
>     /**
>      * Creates and returns a CompletableFuture that is completed with
>      * the result of the given function of this and the other given
>      * CompletableFuture's results if/when both complete normally.
>      *
>      * @return the new CompletableFuture
>      */
>     public <U,V> CompletableFuture<V> and(CompletableFuture<? extends 
> U> x,
>                                           BiFunction<? super T,? super 
> U,? extends V> fn);
>
>     /**
>      * Creates and returns a CompletableFuture that is completed with
>      * the result of the given function of either this or the other
>      * given CompletableFuture's results if/when either complete
>      * normally.
>      *
>      * @return the new CompletableFuture
>      */
>     public <U> CompletableFuture<U> or(CompletableFuture<? extends T> x,
>                                        BiFunction<? super T,? super T, 
> ? extends U> fn);

Thinking a little more about this one, fn should be a Function not a 
BiFunction
given that only one of the two completables needs to complete.

>
>     // Action (vs function) forms
>
>     /**
>      * Creates and returns a CompletableFuture that is completed
>      * after performing the given action with the result of this
>      * CompletableFuture if/when it completes normally.
>      *
>      * @return the new CompletableFuture
>      */
>     public CompletableFuture<Void> then(Block<? super T> action);
>
>     /**
>      * Creates and returns a CompletableFuture that is completed
>      * after performing the given action with the result of the given
>      * function of this and the other given CompletableFuture's
>      * results if/when both complete normally.
>      *
>      * @return the new CompletableFuture
>      */
>     public <U> CompletableFuture<Void> and(CompletableFuture<? extends 
> U> x,
>                                            BiBlock<? super T, ? super 
> U> action);

I think that CompletableFuture<?> is better as return type than 
CompletableFuture<Void>
otherwise users may want to declare a local variable Void.

> /**
>      * Creates and returns a CompletableFuture that is completed
>      * after performing the given action with the result of either
>      * this or the other given CompletableFuture's results if/when
>      * either complete normally.
>      *
>      * @return the new CompletableFuture
>      */
>     public CompletableFuture<Void> or(CompletableFuture<? extends T> x,
>                                       BiBlock<? super T, ? super T> 
> action);

see above.

>
>     /**
>      * Creates and returns a CompletableFuture that is completed after
>      * performing the given action with the exception triggering this
>      * CompletableFuture's completion if/when it completes
>      * exceptionally.
>      *
>      * @return the new CompletableFuture
>      */
>     public CompletableFuture<Void> exceptionally(Block<Throwable> 
> action);

see above.

>
>     // extracting results
>
>     /**
>      * Returns the value when complete, or throws an (unchecked)
>      * exception if completed exceptionally. (The checked exception
>      * variant is available using the timed form of get.)
>      */
>     public T get();
>
>     /**
>      * Returns the value if completed, else the given valueIfAbsent.
>      */
>     public T getNow(T valueIfAbsent);

still think it should use a supplier as parameter and not the value.

>
>     /**
>      * Waits if necessary for at most the given time for the computation
>      * to complete, and then retrieves its result, if available.
>      *
>      * @param timeout the maximum time to wait
>      * @param unit the time unit of the timeout argument
>      * @return the computed result
>      * @throws CancellationException if the computation was cancelled
>      * @throws ExecutionException if the computation threw an
>      * exception
>      * @throws InterruptedException if the current thread was interrupted
>      * while waiting
>      * @throws TimeoutException if the wait timed out
>      */
>     T get(long timeout, TimeUnit unit)
>         throws InterruptedException, ExecutionException, 
> TimeoutException;
>
>     // misc
>
>     /**
>      * Whether or not already completed, sets the value subsequently
>      * returned by method get() and related methods to the given
>      * value. This method is designed primarily for use in recovery
>      * actions.
>      *
>      * @param value the completion value
>      */
>     public void force(T value);
>
>     /**
>      * Returns true if this CompletableFuture is in the process of
>      * completing but has not yet completed. This method is designed
>      * to help diagnose cases in which supplied completion functions
>      * become "stuck" in the process of completion.
>      */
>     public boolean isCompleting();
>
>     /**
>      * Attempts to cancel further processing of this task. This
>      * attempt will fail if already completed. If successful,
>      * subsequent calls to {@link #isCancelled}, {@link #isDone}, and
>      * {@code cancel} will return {@code true} and calls to {@link
>      * #get} and related methods will result in {@code
>      * CancellationException}.
>      *
>      * @param mayInterruptIfRunning this value has no effect in the
>      * default implementation because interrupts are not used to
>      * control processing.
>      *
>      * @return {@code true} if this task is now cancelled
>      */
>     public boolean cancel(boolean mayInterruptIfRunning);
>
>     /**
>      * Returns {@code true} if this CompletableFuture was cancelled
>      * before it completed normally.
>      *
>      * @return {@code true} if this CompletableFuture was cancelled
>      * before it completed normally
>      */
>     public boolean isCancelled();
>
>     /**
>      * Returns {@code true} if completed in any fashion: normally,
>      * exceptionally, or cancellation.
>      *
>      * @return {@code true} if completed
>      */
>     public boolean isDone();
> }
>

Rémi



More information about the lambda-libs-spec-observers mailing list