CompletableFuture

1.官方文檔

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.

When two or more threads attempt to complete, 
completeExceptionally, or cancel a CompletableFuture, only one 
of them succeeds.

In addition to these and related methods for directly 
manipulating status and results, CompletableFuture implements 
interface CompletionStage with the following policies:
* Actions supplied for dependent completions of non-async 
  methods may be performed by the thread that completes the 
  current CompletableFuture, or by any other caller of a 
  completion method.
* All async methods without an explicit Executor argument are 
  performed using the ForkJoinPool.commonPool() (unless it 
  does not support a parallelism level of at least two, in which 
  case, a new Thread is created to run each task). To simplify 
  monitoring, debugging, and tracking, all generated 
  asynchronous tasks are instances of the marker interface 
  CompletableFuture.AsynchronousCompletionTask.
* All CompletionStage methods are implemented independently 
  of other public methods, so the behavior of one method is not 
  impacted by overrides of others in subclasses.

CompletableFuture also implements Future with the following 
policies:
* Since (unlike FutureTask) this class has no direct control over 
  the computation that causes it to be completed, cancellation is 
  treated as just another form of exceptional completion. Method 
  cancel has the same effect as completeExceptionally(new 
  CancellationException()). Method isCompletedExceptionally() 
  can be used to determine if a CompletableFuture completed in 
  any exceptional fashion.
* In case of exceptional completion with a CompletionException, 
  methods get() and get(long, TimeUnit) throw an 
  ExecutionException with the same cause as held in the 
  corresponding CompletionException. To simplify usage in most 
  contexts, this class also defines methods join() and getNow(T) 
  that instead throw the CompletionException directly in these 
  cases.

可以顯式完成的Future(設置其值和狀態),並且可以用作CompletionStage,支持在完成時觸發依賴函數和操作。

當兩個或多個線程嘗試complete、completeExceptionally或cancel CompletableFuture時,只有一個能成功。

除了直接操作狀態和結果的這些以及相關方法之外,CompletableFuture還使用以下策略實現接口CompletionStage:

  • 爲非異步方法的依賴完成提供的動作可以由完成當前CompletableFuture的線程執行,或者由完成方法的任何其他調用者執行。
  • 所有沒有顯式Executor參數的異步方法都是使用ForkJoinPool.commonPool()執行的(除非它不支持至少兩個並行級別,在這種情況下,創建一個新的Thread來運行每個任務)。爲了簡化監視、調試和跟蹤,所有生成的異步任務都是標記接口CompletableFuture.AsynchronousCompletionTask的實例。
  • 所有CompletionStage方法都是獨立於其他公共方法實現的,因此一個方法的行爲不會受到子類中其他方法的覆蓋的影響。

CompletableFuture還通過以下策略實現Future:

  • 由於(與FutureTask不同)此類無法直接控制導致其完成的計算,因此取消僅被視爲異常完成的另一種形式。cancel方法等效於completeExceptionally(new CancellationException())。方法isCompletedExceptionally()可用於確定CompletableFuture是否以任何異常方式完成。
  • 當以CompletionException異常完成時,則方法get()和get(long,TimeUnit)拋出ExecutionException,其原因與相應的CompletionException中保存的原因相同。爲了簡化大多數上下文中的使用,此類還定義了join()和getNow(T)方法,它們在這些情況下直接拋出CompletionException。

1.1 實現說明

A CompletableFuture may have dependent completion actions,
collected in a linked stack. It atomically completes by CASing
a result field, and then pops off and runs those actions. This
applies across normal vs exceptional outcomes, sync vs async
actions, binary triggers, and various forms of completions.

Non-nullness of field result (set via CAS) indicates done.  An
AltResult is used to box null as a result, as well as to hold
exceptions.  Using a single field makes completion simple to
detect and trigger.  Encoding and decoding is straightforward
but adds to the sprawl of trapping and associating exceptions
with targets.  Minor simplifications rely on (static) NIL (to
box null results) being the only AltResult with a null
exception field, so we don't usually need explicit comparisons.
Even though some of the generics casts are unchecked (see
SuppressWarnings annotations), they are placed to be
appropriate even if checked.

Dependent actions are represented by Completion objects linked
as Treiber stacks headed by field "stack". There are Completion
classes for each kind of action, grouped into single-input
(UniCompletion), two-input (BiCompletion), projected
(BiCompletions using either (not both) of two inputs), shared
(CoCompletion, used by the second of two sources), zero-input
source actions, and Signallers that unblock waiters. Class
Completion extends ForkJoinTask to enable async execution
(adding no space overhead because we exploit its "tag" methods
to maintain claims). It is also declared as Runnable to allow
usage with arbitrary executors.

Support for each kind of CompletionStage relies on a separate
class, along with two CompletableFuture methods:

* A Completion class with name X corresponding to function,
  prefaced with "Uni", "Bi", or "Or". Each class contains
  fields for source(s), actions, and dependent. They are
  boringly similar, differing from others only with respect to
  underlying functional forms. We do this so that users don't
  encounter layers of adaptors in common usages. We also
  include "Relay" classes/methods that don't correspond to user
  methods; they copy results from one stage to another.

* Boolean CompletableFuture method x(...) (for example
  uniApply) takes all of the arguments needed to check that an
  action is triggerable, and then either runs the action or
  arranges its async execution by executing its Completion
  argument, if present. The method returns true if known to be
  complete.

* Completion method tryFire(int mode) invokes the associated x
  method with its held arguments, and on success cleans up.
  The mode argument allows tryFire to be called twice (SYNC,
  then ASYNC); the first to screen and trap exceptions while
  arranging to execute, and the second when called from a
  task. (A few classes are not used async so take slightly
  different forms.)  The claim() callback suppresses function
  invocation if already claimed by another thread.

* CompletableFuture method xStage(...) is called from a public
  stage method of CompletableFuture x. It screens user
  arguments and invokes and/or creates the stage object.  If
  not async and x is already complete, the action is run
  immediately.  Otherwise a Completion c is created, pushed to
  x's stack (unless done), and started or triggered via
  c.tryFire.  This also covers races possible if x completes
  while pushing.  Classes with two inputs (for example BiApply)
  deal with races across both while pushing actions.  The
  second completion is a CoCompletion pointing to the first,
  shared so that at most one performs the action.  The
  multiple-arity methods allOf and anyOf do this pairwise to
  form trees of completions.

Note that the generic type parameters of methods vary according
to whether "this" is a source, dependent, or completion.

Method postComplete is called upon completion unless the target
is guaranteed not to be observable (i.e., not yet returned or
linked). Multiple threads can call postComplete, which
atomically pops each dependent action, and tries to trigger it
via method tryFire, in NESTED mode.  Triggering can propagate
recursively, so NESTED mode returns its completed dependent (if
one exists) for further processing by its caller (see method
postFire).

Blocking methods get() and join() rely on Signaller Completions
that wake up waiting threads.  The mechanics are similar to
Treiber stack wait-nodes used in FutureTask, Phaser, and
SynchronousQueue. See their internal documentation for
algorithmic details.

Without precautions, CompletableFutures would be prone to
garbage accumulation as chains of Completions build up, each
pointing back to its sources. So we null out fields as soon as
possible (see especially method Completion.detach). The
screening checks needed anyway harmlessly ignore null arguments
that may have been obtained during races with threads nulling
out fields.  We also try to unlink fired Completions from
stacks that might never be popped (see method postFire).
Completion fields need not be declared as final or volatile
because they are only visible to other threads upon safe
publication.

CompletableFuture可能具有相關的完成操作,收集在棧中。它通過CASing更新結果字段以原子方式完成,然後彈出並運行這些操作。這適用於正常與異常結果,同步與異步動作,binary觸發器和各種形式的完成。

字段結果的非零值(通過CAS設置)表示已完成。 AltResult將null裝箱並作爲結果,以及保存異常。使用單個字段可以使檢測和觸發變得簡單。編碼和解碼很簡單,但會增加陷阱並將異常與目標相關聯。較小的簡化依賴於(靜態)NIL(to box null results)是唯一具有null異常字段的AltResult,因此我們通常不需要進行顯式比較。即使某些泛型類型轉換未經檢查(請參閱SuppressWarnings註釋),即使經過檢查,它們放置的位置也是合適的。

相關動作由作爲Treiber棧鏈接的Completion對象表示,該棧由字段“stack”表示。每種動作都有完成類,分爲單輸入(UniCompletion),雙輸入(BiCompletion),projected(BiCompletions使用兩個輸入中的一個),共享(CoCompletion,兩個來源中的第二個),零輸入源動作,以及解鎖等待線程的Signallers。類Completion擴展了ForkJoinTask以啓用異步執行(不添加空間開銷,因爲我們利用其“tag”方法來維護聲明)。它也被聲明爲Runnable以允許使用任意執行程序。

對每種CompletionStage的支持依賴於一個單獨的類,以及兩個CompletableFuture方法:

  • 名稱爲X的Completion類,對應於函數,前綴爲“Uni”,“Bi”或“Or”。每個類都包含source(s)、actions和dependent的字段。它們非常相似,僅與底層功能形式有所不同。我們這樣做是爲了讓用戶在常見用法中不會遇到適配器層。我們還包括與用戶方法不對應的“Relay”類/方法;他們將結果從一個stage複製到另一個。

  • Boolean CompletableFuture方法x(...)(例如uniApply)獲取檢查操作是否可觸發所需的所有參數,然後運行操作或通過執行其Completion參數(如果存在)安排其異步執行。如果已知完成,則該方法返回true。

  • 完成方法tryFire(int mode)調用以其參數調用關聯的x方法,並在成功時清除。 mode參數允許tryFire被調用兩次(SYNC,然後是ASYNC);第一個在安排執行時屏蔽和捕獲異常,第二個在任務調用時 (一些類不使用異步,因此採用略有不同的形式。)如果另一個線程已經claim了,則claim()回調會抑制函數調用。

  • CompletableFuture方法xStage(...)從CompletableFuture x的公共stage方法處調用。它會篩選用戶參數並調用和/或創建stage對象。如果不是異步並且x已經完成,則立即執行操作。否則,創建Completion c,壓入x的堆棧(除非完成),並通過c.tryFire啓動或觸發。如果x在壓入時完成,這也包括可能的爭用。具有兩個輸入的類(例如BiApply)在push動作時處理兩者之間的爭用。第二個completion是指向第一個的CoCompletion,共享以便最多隻執行一個動作。多重方法allOf和anyOf成對地形成completions樹。

請注意,方法的泛型類型參數根據“this”是源、依賴還是完成而有所不同。

方法postComplete在完成時被調用,除非保證目標不可觀察(即,尚未返回或鏈接)。多個線程可以調用postComplete,它會自動彈出每個依賴操作,並嘗試在NESTED模式下通過方法tryFire觸發它。觸發可以遞歸傳播,因此NESTED模式返回其完成的依賴(如果存在)以供其調用者進一步處理(請參閱postFire方法)。

阻塞方法get()和join()依賴於喚醒等待線程的Signaller Completions。這些機制類似於FutureTask、Phaser和SynchronousQueue中使用的Treiber堆棧等待節點。有關算法詳細信息,請參閱其內部文檔。

如果沒有預防措施,CompletableFutures將容易導致垃圾堆積,因爲Completions鏈的堆積,每個都指向其源。 所以我們儘快使字段null out(特別參見方法Completion.detach)。 無論如何,篩選檢查無害地忽略了null參數,其在使用線程將字段置零的比賽期間可能獲得的。 我們還嘗試從可能永遠不會彈出的棧中取消鏈接已fired的Completions(請參閱方法postFire)。 Completion字段不需要聲明爲final或volatile,因爲它們僅在安全發佈時對其他線程可見。

2.爲什麼引入CompletableFuture?

2.1 回調

回調函數比較通用的解釋是,它是一個通過函數指針調用的函數。如果你把函數的指針(地址)作爲參數傳遞給另一個函數,當這個指針被用爲調用它所指向的函數時,我們就說這是回調函數。回調函數不是由該函數的實現方直接調用,而是在特定的事件或條件發生時由另外一方調用的,用於對該事件或條件進行響應。

回調函數的機制:

  • 定義一個回調函數;
  • 提供函數實現的一方在初始化時候,將回調函數的函數指針註冊給調用者;
  • 當特定的事件或條件發生的時候,調用者使用函數指針調用回調函數對事件進行處理。

2.2 回調方式的異步編程

JDK5 新增了 Future 接口,用於描述一個異步計算的結果。雖然 Future 以及相關使用方法提供了異步執行任務的能力,但是對於結果的獲取卻是很不方便,只能通過阻塞或者輪詢的方式得到任務的結果。阻塞的方式顯然和我們的異步編程的初衷相違背,輪詢的方式又會耗費無謂的 CPU 資源,而且也不能及時地得到計算結果。

爲什麼不能用觀察者設計模式呢?即當計算結果完成及時通知監聽者。
有一些開源框架實現了我們的設想:

  • 例如 Netty 的 ChannelFuture 類擴展了 Future 接口,通過提供 addListener 方法實現支持回調方式的異步編程。Netty 中所有的 I/O 操作都是異步的,這意味着任何的 I/O 調用都將立即返回,而不保證這些被請求的 I/O 操作在調用結束的時候已經完成。取而代之地,你會得到一個返回的 ChannelFuture 實例,這個實例將給你一些關於 I/O 操作結果或者狀態的信息。當一個 I/O 操作開始的時候,一個新的 Future 對象就會被創建。在開始的時候,新的 Future 是未完成的狀態--它既非成功、失敗,也非被取消,因爲 I/O 操作還沒有結束。如果 I/O 操作以成功、失敗或者被取消中的任何一種狀態結束了,那麼這個 Future 將會被標記爲已完成,幷包含更多詳細的信息(例如:失敗的原因)。請注意,即使是失敗和被取消的狀態,也是屬於已完成的狀態。
  • Google guava也提供了通用的擴展Future:ListenableFuture、SettableFuture 以及輔助類Futures等,方便異步編程。
  • Scala也提供了簡單易用且功能強大的Future/Promise異步編程模式。
  • CompletableFuture提供了非常強大的 Future 的擴展功能,可以幫助我們簡化異步編程的複雜性,並且提供了函數式編程的能力,可以通過回調的方式處理計算結果,也提供了轉換和組合 CompletableFuture 的方法。

2.3 CompletableFuture

處理非阻塞調用的傳統方法是使用事件處理器,程序員爲任務完成之後要出現的動作註冊一個處理器。但是,要嘗試在一組事件處理器中實現一個控制流會很困難。

CompletableFuture提供了一種候選方法,與事件處理器不同,CompletableFuture可以組合。利用CompletableFuture,可以指定希望做什麼,以及希望以什麼順序執行這些工作。這些動作不會立即發生,不過重要的是將所有代碼放在一起。

CompletableFuture提供了非常強大的 Future 的擴展功能,可以幫助我們簡化異步編程的複雜性,並且提供了函數式編程的能力,可以通過回調的方式處理計算結果,也提供了轉換和組合 CompletableFuture 的方法。

對於阻塞或者輪詢方式,依然可以通過 CompletableFuture 類的 CompletionStage 和 Future 接口方式支持。

CompletableFuture 類聲明瞭 CompletionStage 接口,CompletionStage 接口實際上提供了同步或異步運行計算的舞臺,所以我們可以通過實現多個 CompletionStage 命令,並且將這些命令串聯在一起的方式實現多個命令之間的觸發。

3.每一種方法的三種形式

    public <U> CompletableFuture<U> thenApply(
        Function<? super T,? extends U> fn) {
        return uniApplyStage(null, fn);
    }

    public <U> CompletableFuture<U> thenApplyAsync(
        Function<? super T,? extends U> fn) {
        return uniApplyStage(asyncPool, fn);
    }

    public <U> CompletableFuture<U> thenApplyAsync(
        Function<? super T,? extends U> fn, Executor executor) {
        return uniApplyStage(screenExecutor(executor), fn);
    }

    private static final boolean useCommonPool =
        (ForkJoinPool.getCommonPoolParallelism() > 1);

    /**
     * Default executor -- ForkJoinPool.commonPool() unless it cannot
     * support parallelism.
     */
    private static final Executor asyncPool = useCommonPool ?
        ForkJoinPool.commonPool() : new ThreadPerTaskExecutor();

    /** Fallback if ForkJoinPool.commonPool() cannot support parallelism */
    static final class ThreadPerTaskExecutor implements Executor {
        public void execute(Runnable r) { new Thread(r).start(); }
    }
  • 非異步方法由當前線程或調用線程執行
  • 不帶executor的異步方法使用asyncPool來執行
    1)如果不支持多線程,則新建一個線程專門執行
    2)否則使用ForkJoinPool.commonPool()執行
  • 另一種異步方法使用executor執行

4.創建CompletableFuture

    public CompletableFuture() {
    }

    private CompletableFuture(Object r) {
        this.result = r;
    }
    public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier) {
        return asyncSupplyStage(asyncPool, supplier);
    }

    public static <U> CompletableFuture<U> supplyAsync(Supplier<U> supplier,
                                                       Executor executor) {
        return asyncSupplyStage(screenExecutor(executor), supplier);
    }
    public static CompletableFuture<Void> runAsync(Runnable runnable) {
        return asyncRunStage(asyncPool, runnable);
    }

    public static CompletableFuture<Void> runAsync(Runnable runnable,
                                                   Executor executor) {
        return asyncRunStage(screenExecutor(executor), runnable);
    }

5.中間組合操作

  • Runnable類型的參數會忽略計算的結果
  • Consumer是純消費計算結果,BiConsumer會組合另外一個CompletionStage純消費
  • Function會對計算結果做轉換,BiFunction會組合另外一個CompletionStage的計算結果做轉換。

5.1 轉換

thenApply功能相當於將CompletableFuture<T>轉換成CompletableFuture<U>。

    public <U> CompletableFuture<U> thenApply(
        Function<? super T,? extends U> fn) {
        return uniApplyStage(null, fn);
    }
    public <U> CompletableFuture<U> applyToEither(
        CompletionStage<? extends T> other, Function<? super T, U> fn) {
        return orApplyStage(null, other, fn);
    }

其實從功能上來講,thenCombine的功能更類似thenAcceptBoth,只不過thenAcceptBoth是純消費,它的函數參數沒有返回值,而thenCombine的函數參數fn有返回值。

    public <U,V> CompletableFuture<V> thenCombine(
        CompletionStage<? extends U> other,
        BiFunction<? super T,? super U,? extends V> fn) {
        return biApplyStage(null, other, fn);
    }

這一組方法接受一個Function作爲參數,這個Function的輸入是當前的CompletableFuture的計算值,返回結果將是一個新的CompletableFuture,這個新的CompletableFuture會組合原來的CompletableFuture和函數返回的CompletableFuture。

    public <U> CompletableFuture<U> thenCompose(
        Function<? super T, ? extends CompletionStage<U>> fn) {
        return uniComposeStage(null, fn);
    }

示例:

public class Test3 {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
            return 100;
        });
        CompletableFuture<String> f =  future.thenApplyAsync(i -> i * 10).thenApply(i -> i.toString());
        System.out.println(f.get());
    }
}

結果:

1000
public class Test6 {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
            return 100;
        });
        CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
            return "abc";
        });
        CompletableFuture<String> f =  future.thenCombine(future2, (x,y) -> y + "-" + x);
        System.out.println(f.get());
    }
}

結果:

abc-100
public class Test7 {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
            return 100;
        });
        CompletableFuture<String> f =  future.thenCompose( i -> {
            return CompletableFuture.supplyAsync(() -> {
                return (i * 10) + "";
            });
        });
        System.out.println(f.get());
    }
}

結果:

1000

5.2 消費

thenAccept只對結果執行Action,而不返回新的計算值。

    public CompletableFuture<Void> thenAccept(Consumer<? super T> action) {
        return uniAcceptStage(null, action);
    }
    public <U> CompletableFuture<Void> thenAcceptBoth(
        CompletionStage<? extends U> other,
        BiConsumer<? super T, ? super U> action) {
        return biAcceptStage(null, other, action);
    }
    public <U> CompletableFuture<U> applyToEither(
        CompletionStage<? extends T> other, Function<? super T, U> fn) {
        return orApplyStage(null, other, fn);
    }

示例:

public class Test4 {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
            return 100;
        });
        CompletableFuture<Void> f =  future.thenAccept(System.out::println);
        System.out.println(f.get());
    }
}

結果:

100
null
public class Test5 {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
            return 100;
        });
        CompletableFuture<Void> f =  future.thenAcceptBoth(CompletableFuture.completedFuture(10), (x, y) -> System.out.println(x * y));
        System.out.println(f.get());
    }
}

結果:

1000
null

5.3 運行

thenRun更徹底地,下面一組方法當計算完成的時候會執行一個Runnable,與thenAccept不同,Runnable並不使用CompletableFuture計算的結果。

    public CompletableFuture<Void> thenRun(Runnable action) {
        return uniRunStage(null, action);
    }
    public CompletableFuture<Void> runAfterBoth(CompletionStage<?> other,
                                                Runnable action) {
        return biRunStage(null, other, action);
    }

    public CompletableFuture<Void> runAfterEither(CompletionStage<?> other,
                                                  Runnable action) {
        return orRunStage(null, other, action);
    }

5.4 批量

    public static CompletableFuture<Void> allOf(CompletableFuture<?>... cfs) {
        return andTree(cfs, 0, cfs.length - 1);
    }
    public static CompletableFuture<Object> anyOf(CompletableFuture<?>... cfs) {
        return orTree(cfs, 0, cfs.length - 1);
    }

6.終止操作

    public <U> CompletableFuture<U> handle(
        BiFunction<? super T, Throwable, ? extends U> fn) {
        return uniHandleStage(null, fn);
    }
    public CompletableFuture<T> whenComplete(
        BiConsumer<? super T, ? super Throwable> action) {
        return uniWhenCompleteStage(null, action);
    }
    public CompletableFuture<T> exceptionally(
        Function<Throwable, ? extends T> fn) {
        return uniExceptionallyStage(fn);
    }

7.通過阻塞或者輪詢的方式獲得結果

get在遇到底層異常時,會拋出受查異常ExecutionException。

    public T get() throws InterruptedException, ExecutionException {
        Object r;
        return reportGet((r = result) == null ? waitingGet(true) : r);
    }

    public T get(long timeout, TimeUnit unit)
        throws InterruptedException, ExecutionException, TimeoutException {
        Object r;
        long nanos = unit.toNanos(timeout);
        return reportGet((r = result) == null ? timedGet(nanos) : r);
    }

join在遇到底層的異常時,會拋出未受查的CompletionException。

    public T join() {
        Object r;
        return reportJoin((r = result) == null ? waitingGet(false) : r);
    }
    public T getNow(T valueIfAbsent) {
        Object r;
        return ((r = result) == null) ? valueIfAbsent : reportJoin(r);
    }

示例:

public class Test1 {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
            int i = 1/0;
            return 100;
        });
        System.out.println(future.get());
    }
}

結果:

Exception in thread "main" java.util.concurrent.ExecutionException: java.lang.ArithmeticException: / by zero
    at java.util.concurrent.CompletableFuture.reportGet(CompletableFuture.java:357)
    at java.util.concurrent.CompletableFuture.get(CompletableFuture.java:1895)
    at com.enjoy.learn.core.concurrency.completablefuture.Test1.main(Test1.java:19)
Caused by: java.lang.ArithmeticException: / by zero
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        CompletableFuture<Integer> future = CompletableFuture.supplyAsync(() -> {
            int i = 1/0;
            return 100;
        });
        System.out.println(future.join());
    }

結果:

Exception in thread "main" java.util.concurrent.CompletionException: java.lang.ArithmeticException: / by zero
    at java.util.concurrent.CompletableFuture.encodeThrowable(CompletableFuture.java:273)
    at java.util.concurrent.CompletableFuture.completeThrowable(CompletableFuture.java:280)
    at java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1592)
    at java.util.concurrent.CompletableFuture$AsyncSupply.exec(CompletableFuture.java:1582)
    at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:289)
    at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1056)
    at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1692)
    at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157)
Caused by: java.lang.ArithmeticException: / by zero

8.源碼解析

supplyAsync調用asyncSupplyStage(asyncPool, supplier):

    static <U> CompletableFuture<U> asyncSupplyStage(Executor e,
                                                     Supplier<U> f) {
        if (f == null) throw new NullPointerException();
        CompletableFuture<U> d = new CompletableFuture<U>();
        e.execute(new AsyncSupply<U>(d, f));
        return d;
    }
    static final class AsyncSupply<T> extends ForkJoinTask<Void>
            implements Runnable, AsynchronousCompletionTask {
        CompletableFuture<T> dep; Supplier<T> fn;
        AsyncSupply(CompletableFuture<T> dep, Supplier<T> fn) {
            this.dep = dep; this.fn = fn;
        }

        public final Void getRawResult() { return null; }
        public final void setRawResult(Void v) {}
        public final boolean exec() { run(); return true; }

        public void run() {
            CompletableFuture<T> d; Supplier<T> f;
            if ((d = dep) != null && (f = fn) != null) {
                dep = null; fn = null;
                if (d.result == null) {
                    try {
                        d.completeValue(f.get());
                    } catch (Throwable ex) {
                        d.completeThrowable(ex);
                    }
                }
                d.postComplete();
            }
        }
    }

postComplete方法:

    /**
     * Pops and tries to trigger all reachable dependents.  Call only
     * when known to be done.
     */
    final void postComplete() {
        /*
         * On each step, variable f holds current dependents to pop
         * and run.  It is extended along only one path at a time,
         * pushing others to avoid unbounded recursion.
         */
        CompletableFuture<?> f = this; Completion h;
        while ((h = f.stack) != null ||
               (f != this && (h = (f = this).stack) != null)) {
            CompletableFuture<?> d; Completion t;
            if (f.casStack(h, t = h.next)) {
                if (t != null) {
                    if (f != this) {
                        pushStack(h);
                        continue;
                    }
                    h.next = null;    // detach
                }
                f = (d = h.tryFire(NESTED)) == null ? this : d;
            }
        }
    }
    volatile Object result;       // Either the result or boxed AltResult
    volatile Completion stack;    // Top of Treiber stack of dependent actions

stack:保存的是依靠當前的CompletableFuture一串任務,完成即觸發(回調)




tryFire是Completion中聲明的方法:


    abstract static class Completion extends ForkJoinTask<Void>
        implements Runnable, AsynchronousCompletionTask {
        volatile Completion next;      // Treiber stack link

        /**
         * Performs completion action if triggered, returning a
         * dependent that may need propagation, if one exists.
         *
         * @param mode SYNC, ASYNC, or NESTED
         */
        abstract CompletableFuture<?> tryFire(int mode);

        /** Returns true if possibly still triggerable. Used by cleanStack. */
        abstract boolean isLive();

        public final void run()                { tryFire(ASYNC); }
        public final boolean exec()            { tryFire(ASYNC); return true; }
        public final Void getRawResult()       { return null; }
        public final void setRawResult(Void v) {}
    }
    // Modes for Completion.tryFire. Signedness matters.
    static final int SYNC   =  0;
    static final int ASYNC  =  1;
    static final int NESTED = -1;

參考

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章