- 型パラメータ:
T- スコープで実行されたタスクの結果タイプ
- すべての実装されたインタフェース:
AutoCloseable
StructuredTaskScopeは、タスクが複数の同時サブタスクに分割され、独自のスレッドで実行されるケースと、メイン・タスクを続行する前にサブタスクが完了する必要があるケースをサポートします。 StructuredTaskScopeを使用すると、構造化プログラミングの順次演算と同様に、同時演算の存続期間が「構文ブロック」によって制限されるようにできます。
基本的な使用方法
StructuredTaskScopeは、そのパブリック・コンストラクタのいずれかを使用して作成されます。 タスクを実行するためにスレッドを開始するforkメソッド、すべてのスレッドが終了するまで待機するjoinメソッド、およびタスク範囲を閉じるためのcloseメソッドを定義します。 APIは、 try-with-resources構成で使用することを目的としています。 blockのコードは、forkメソッドを使用してスレッドをフォークし、サブタスクを実行し、スレッドがjoinメソッドで終了するまで待機してから「結果を処理」を実行するということを意図しています。 結果の処理には、例外の処理や再スローが含まれる場合があります。
try (var scope = new StructuredTaskScope<Object>()) {
Future<Integer> future1 = scope.fork(task1);
Future<String> future2 = scope.fork(task2);
scope.join();
... process results/exceptions ...
} // close
joinおよびcloseメソッドはowner (タスク・スコープを開いた/作成したスレッド)によってのみ起動でき、所有者がフォーク後にjoinメソッドを呼び出さなかった場合、closeメソッドはクローズ後に例外をスローします。
StructuredTaskScopeは、タスク・スコープを閉じずに停止するshutdownメソッドを定義します。 シャットダウンは、サブタスクが結果(または例外)で完了し、他の未完了サブタスクの結果が不要になった場合に役立ちます。 所有者がjoinメソッドで待機している間にサブタスクがshutdownを起動すると、joinがウェイ・ク アップされ、すべての未完了スレッドがinterruptedになり、新しいスレッドがタスク・スコープで開始されなくなります。
一般的なケースのポリシーを持つサブクラス
StructuredTaskScopeの2つのサブクラスは、一般的な場合にポリシーを実装するために定義されています:
-
ShutdownOnSuccessは、最初の結果を取得し、タスク範囲をシャットダウンして未完了のスレッドを中断し、所有者をウェイ・ク アップします。 このクラスは、サブタスクの結果が("任意の起動")を実行し、他の未完了タスクの結果を待機する必要がない場合に意図されています。 最初の結果を取得するメソッド、またはすべてのサブタスクが失敗した場合に例外をスローするメソッドを定義します。 -
ShutdownOnFailureは、最初の例外を取得し、タスク範囲を停止します。 このクラスは、すべてのサブタスクの結果が("すべて起動")を必要とする場合を対象としています。サブタスクが失敗した場合、他の未完了サブタスクの結果は不要になります。 サブタスクのいずれかが失敗した場合に例外をスローするメソッドを定義する場合。
次に、2つのクラスを使用する2つの例を示します。 どちらの場合も、2つのURLのロケーション"left"および"right"からリソースをフェッチするために、サブタスクのペアがフォークされます。 最初の例では、正常に完了する最初のサブタスクの結果を取得するShutdownOnSuccessオブジェクトを作成し、タスク範囲を停止してもう一方のサブタスクを取り消します。 サブタスクのいずれかが結果で完了するか、両方のサブタスクが失敗するまで、メイン・タスクはjoinで待機します。 result(Function)メソッドを起動して取得結果を取得します。 両方のサブタスクが失敗した場合、このメソッドは、原因としていずれかのサブタスクから例外とともにWebApplicationExceptionをスローします。
try (var scope = new StructuredTaskScope.ShutdownOnSuccess<String>()) {
scope.fork(() -> fetch(left));
scope.fork(() -> fetch(right));
scope.join();
String result = scope.result(e -> new WebApplicationException(e));
...
}
joinUntil(Instant)で待機します。 throwIfFailed(Function)を起動して、いずれかのサブタスクが失敗した場合に例外をスローします。 サブタスクが失敗しない場合、このメソッドはno-opです。 メイン・タスクでは、FutureのresultNow()メソッドを使用して結果を取得します。
Instant deadline = ...
try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
Future<String> future1 = scope.fork(() -> query(left));
Future<String> future2 = scope.fork(() -> query(right));
scope.joinUntil(deadline);
scope.throwIfFailed(e -> new WebApplicationException(e));
// both subtasks completed successfully
String result = Stream.of(future1, future2)
.map(Future::resultNow)
.collect(Collectors.joining(", ", "{ ", " }"));
...
}
StructuredTaskScopeの拡張
StructuredTaskScopeを拡張し、handleCompleteをオーバーライドして、ShutdownOnSuccessおよびShutdownOnFailureによって実装されたポリシー以外のポリシーを実装できます。 メソッドをオーバーライドすると、たとえば、結果で完了したサブタスクの結果を収集し、失敗したサブタスクを無視できます。 サブタスクが失敗した場合に例外が収集される場合があります。 shutdownメソッドを起動して停止し、一部の条件が発生したときにjoinがウェイ・ク アップする場合があります。
サブクラスは、通常、joinメソッドの後に実行されるコードに対して使用可能な結果、状態またはその他の結果を作成するメソッドを定義します。 結果を収集し、失敗したサブタスクを無視するサブクラスは、結果のコレクションを返すメソッドを定義できます。 サブタスクが失敗したときに停止するポリシーを実装するサブクラスは、失敗する最初のサブタスクの例外を取得するメソッドを定義できます。
次に、正常に完了したサブタスクの結果を収集するStructuredTaskScope実装の例を示します。 結果を取得するためにメイン・タスクで使用されるメソッドresults()を定義します。
class MyScope<T> extends StructuredTaskScope<T> {
private final Queue<T> results = new ConcurrentLinkedQueue<>();
MyScope() {
super(null, Thread.ofVirtual().factory());
}
@Override
protected void handleComplete(Future<T> future) {
if (future.state() == Future.State.SUCCESS) {
T result = future.resultNow();
results.add(result);
}
}
// Returns a stream of results from the subtasks that completed successfully
public Stream<T> results() {
return results.stream();
}
}
ツリー構造
StructuredTaskScopesは、新しいタスク範囲を開くときに親子関係が暗黙的に確立されるツリーを形成します:- 親子関係は、タスク・スコープで開始されたスレッドが独自のタスク・スコープを開くと確立されます。 タスク・スコープ"A"で開始されたスレッドで、タスク・スコープ"B"を開くと、タスク・スコープ"A"がタスク・スコープ"B"の親である親子関係が確立されます。
- 親子関係はネストによって確立されます。 スレッドがタスク・スコープ"B"を開き、タスク・スコープ"C" ("B"をクローズする前に)を開くと、包含タスク・スコープ"B"はネストされたタスク・スコープ"C"の親になります。
ツリー構造では、拘束チェックがサポートされます。 メソッド記述の"タスク範囲に含まれるスレッド"というフレーズは、タスク・スコープまたは子孫スコープで開始されたスレッドを意味します。 StructuredTaskScopeでは、現時点ではツリー構造を公開するAPIは定義されません。
特に指定しないかぎり、このクラスのコンストラクタまたはメソッドにnull引数を渡すと、NullPointerExceptionがスローされます。
メモリーの一貫性の影響
Callableタスクの「フォーク」より前、または含まれているスレッドの所有者スレッドでのアクションhappen-beforeそのタスクによって実行されたアクション。次に、happen-beforeタスク結果は、そのFutureを介して取得されます。または、タスク・スコープの「参加」の後にスレッドで実行されたアクションをhappen-beforeします。
- Java言語仕様を参照してください:
-
17.4.5 Happens-beforeオーダー
- 導入されたバージョン:
- 19
-
ネストされたクラスのサマリー
ネストされたクラス修飾子と型クラス説明static final class異常終了する最初のサブタスクの例外を取得するStructuredTaskScope。static final class正常に完了する最初のサブタスクの結果を取得するStructuredTaskScope。 -
コンストラクタのサマリー
コンストラクタコンストラクタ説明仮想スレッドを作成する名前のない構造化タスク・スコープを作成します。StructuredTaskScope(String name, ThreadFactory factory) 指定された名前とスレッド・ファクトリを使用して構造化タスク・スコープを作成します。 -
メソッドのサマリー
-
コンストラクタの詳細
-
StructuredTaskScope
public StructuredTaskScope(String name, ThreadFactory factory) 指定された名前とスレッド・ファクトリを使用して構造化タスク・スコープを作成します。 タスク範囲には、モニタリングおよび管理の目的で任意の名前が付けられます。 スレッド・ファクトリは、タスクが「フォーク」の場合にスレッドをcreateするために使用されます。 タスク・スコープは現在のスレッドによって所有されます。- パラメータ:
name- タスク範囲の名前。NULLにできますfactory- スレッドのファクトリ
-
StructuredTaskScope
public StructuredTaskScope()仮想スレッドを作成する名前のない構造化タスク・スコープを作成します。 タスク・スコープは現在のスレッドによって所有されます。このコンストラクタは、
nullという名前の2引数コンストラクタと、仮想スレッドを作成するスレッド・ファクトリの起動と同等です。- 例外:
UnsupportedOperationException- プレビュー機能が有効になっていない場合
-
-
メソッドの詳細
-
handleComplete
スコープが停止する前にタスクが完了したときに起動されます。handleCompleteメソッドはスレッド・セーフである必要があります。 複数のスレッドによって同時に起動できます。- 実装要件:
- デフォルト実装は何も実行しません。
- パラメータ:
future- 完了済タスク
-
fork
指定されたタスクを実行する新しいスレッドを開始します。新しいスレッドは、タスク・スコープ
ThreadFactoryを使用して作成されます。タスク・スコープが
shutdownになる前にタスクが完了すると、handleメソッドが起動され、完了したタスクが消費されます。handleCompleteメソッドは、タスクが結果または例外で完了したときに実行されます。Futurecancelメソッドを使用してタスク・スコープが停止する前にタスクを取り消すと、cancelを起動するスレッドによってhandleCompleteメソッドが実行されます。 タスクの完了または取消しと同時にタスク範囲が停止した場合、handleCompleteメソッドが起動される場合と実行されない場合があります。このタスク範囲がshutdown (またはシャットダウン処理中)の場合、
forkは、実行されなかったcancelledタスクを表すFutureを返します。このメソッドは、タスク・スコープ所有者またはタスク・スコープに含まれるスレッドによってのみ起動できます。 戻された
Futureオブジェクトのcancelメソッドは、タスク・スコープの所有者またはタスク・スコープに含まれるスレッドに制限されます。cancelメソッドは、別のスレッドからメソッドはWrongThreadExceptionをスローします。 返されたFutureオブジェクト(getなど)上の他のすべてのメソッドは制限されません。- 型パラメータ:
U- 結果の型- パラメータ:
task- 実行するタスク- 戻り値:
- 未来
- 例外:
IllegalStateException- このタスク範囲がクローズされている場合WrongThreadException- 現在のスレッドが所有者またはタスク範囲に含まれるスレッドではない場合RejectedExecutionException- スレッド・ファクトリがタスクを実行するスレッドの作成を拒否した場合
-
join
public StructuredTaskScope<T> join() throws InterruptedExceptionすべてのスレッドが終了するか、タスク範囲がシャットダウンするまで待ちます。 このメソッドは、タスク・スコープで開始されたすべてのスレッドの実行が(タスクとhandleCompleteメソッドの両方)、タスク・スコープを停止するためにshutdownメソッドが呼び出されるか、現在のスレッドがinterruptedになるまで待機します。このメソッドは、タスク・スコープ所有者のみが起動できます。
- 戻り値:
- このタスクの範囲
- 例外:
IllegalStateException- このタスク範囲がクローズされている場合WrongThreadException- 現在のスレッドが所有者でない場合InterruptedException- 待機中に割込みが発生した場合
-
joinUntil
public StructuredTaskScope<T> joinUntil(Instant deadline) throws InterruptedException, TimeoutException 指定された期限まで、すべてのスレッドが終了するか、タスク範囲がシャットダウンするまで待機します。 このメソッドは、タスク・スコープで開始されたすべてのスレッドの実行が(タスクとhandleCompleteメソッドの両方)、タスク・スコープを停止するためにshutdownメソッドが呼び出されるか、現在のスレッドがinterruptedになるか、期限に達するまで待機します。このメソッドは、タスク・スコープ所有者のみが起動できます。
- パラメータ:
deadline- 期限- 戻り値:
- このタスクの範囲
- 例外:
IllegalStateException- このタスク範囲がクローズされている場合WrongThreadException- 現在のスレッドが所有者でない場合InterruptedException- 待機中に割込みが発生した場合TimeoutException- 待機中に期限に達した場合
-
shutdown
public void shutdown()タスク範囲を閉じずに停止します。 タスク・スコープを停止すると、新しいスレッドが開始され、すべての未完了スレッドが中断され、joinメソッドがウェイ・ク アップされます。 シャットダウンは、未完了のサブタスクの結果が不要になった場合に役立ちます。より具体的には、このメソッドは次のとおりです:
- 結果にスレッド「待っていること」があるタスクを「取消」して、待機中のスレッドがウェイ・ク アップするようにします。
- タスク範囲(現在のスレッドを除く)のすべての未完了スレッドを「割り込み」します。
-
join()またはjoinUntil(Instant)で待機している場合、所有者をウェイ・ク アップします。 所有者が待機していない場合、joinまたはjoinUntilへの次のコールはすぐに返されます。
このメソッドが完了すると、すべてのタスクの
Futureオブジェクトは、通常または異常なdoneになります。 スレッド割込みに対して(または迅速に応答)に応答しなかったコードを実行しているため、まだ終了していないスレッドがある可能性があります。 このメソッドはこれらのスレッドを待機しません。 所有者がcloseメソッドを起動してタスク・スコープを閉じると、残りのスレッドが終了するまで待機します。このメソッドは、タスク・スコープ所有者またはタスク・スコープに含まれるスレッドによってのみ起動できます。
- 例外:
IllegalStateException- このタスク範囲がクローズされている場合WrongThreadException- 現在のスレッドが所有者またはタスク範囲に含まれるスレッドではない場合
-
close
public void close()このタスク範囲を閉じます。このメソッドは、最初にタスク範囲(
shutdownメソッドを起動した場合と同じ)をシャットダウンします。 その後、未完了のタスクを実行するスレッドが終了するまで待機します。 中断された場合、このメソッドは、中断ステータスを設定して完了する前にスレッドが終了するのを待機し続けます。このメソッドは、タスク・スコープ所有者のみが起動できます。 タスク・スコープがすでにクローズされている場合、このメソッドを起動する所有者は影響しません。
StructuredTaskScopeは、「構造化方式」で使用することを目的としています。 このメソッドをコールして、ネストされたタスク・スコープを閉じる前にタスク・スコープを閉じる場合、ネストされた各タスク・スコープ(作成した逆の順序)の基礎となる構成を閉じ、このタスク・スコープを閉じて、StructureViolationExceptionをスローします。 スレッドが最初に所有するタスク・スコープを閉じることなく終了すると、終了によって、そのオープン・タスク・スコープの基礎となる構成がクローズされます。 クローズは、タスク範囲が作成された逆の順序で実行されます。 したがって、所有者がこれらのタスク・スコープでフォークされたスレッドが終了するまで待機する必要がある場合、スレッドの終了が遅延する可能性があります。- 定義:
close、インタフェースAutoCloseable- 例外:
IllegalStateException- 所有者がフォーク後に結合を起動しなかった場合、タスク範囲を閉じた後にスローされますWrongThreadException- 現在のスレッドが所有者でない場合StructureViolationException- 構造違反が検出された場合
-