2017-11-25 6 views
0

CompletableFutureのドキュメントは、非同期実行のために次の動作を指定します。CompletableFutureは

それはサポートしていない場合を除き、明示的なキュータ引数なしですべての非同期方法がForkJoinPool#commonPoolを()(使用して実行されています少なくとも2つの並列性レベル。この場合、各タスクを実行するために新しいスレッドが作成されます)。監視、デバッグ、および追跡を簡素化するために、生成されたすべての非同期タスクはマーカーインタフェースAsynchronousCompletionTaskのインスタンスです。

ただし、同期(または少なくとも非同期)メソッドの動作は不明なままです。ほとんどの状況では、コードはそうように、元のスレッドで実行されます。コードの第2のブロックは、時には代わりに共通のプールを使用するように

Thread thread = Thread.currentThread(); 
CompletableFuture.runAsync(() -> { 
     // Should run on the common pool - working as expected 
     assert thread != Thread.currentThread(); 
}).thenRun(() -> { 
     // Returns to running on the thread that launched.. sometimes? 
     assert thread == Thread.currentThread(); 
}).join(); 

しかし、この試験の繰り返しは、一貫性のない結果をもたらします。この状況で意図された動作は何ですか?

答えて

0

CompletableFuture hereのOpenJDK実装を見てみると、競合状態に陥っているような臭いがあります。 runAsync(a).thenRun(b)の行に沿って何かをしているとします。現在のスレッドでthenRun(b)が呼び出される前にaが共通プールスレッドでの実行を終了すると、は、最後に呼び出された時点で現在のスレッドですぐに実行されます。一方、他のスレッドでaが終了する前にthenRun(b)が呼び出された場合は、は、aと同じスレッドで実行され、aが最後に終了します。それは一種の、このようなものだ

:明らかに

class CompletableFuture: 
    function runAsync(a): 
    function c(): 
     run a 
     for each b in the handler stack: 
     run b 
    run c on a different thread 
    return future representing c 
    function thenRun(b): 
    if c is done: 
     run b 
    else: 
     put b in c's handler stack 

thenRuna終了する前に呼び出された場合、bcのスレッドで実行されます。それ以外の場合は、現在のスレッドでbが実行されます。

どのスレッドが何を実行するかという点でより一貫した動作を望む場合は、CompletableFuture#thenRunAsyncを使用してください。これにより、特定のエグゼキュータプールでハンドラが実行されることが保証されます。

関連する問題