- 型パラメータ:
T
- タスク・スコープで実行されるタスクの結果タイプ
- すべての実装されたインタフェース:
AutoCloseable
- 直系の既知のサブクラス:
StructuredTaskScope.ShutdownOnFailurePREVIEW
,StructuredTaskScope.ShutdownOnSuccessPREVIEW
StructuredTaskScope
は、JavaプラットフォームのプレビューAPIです。
StructuredTaskScope
では、タスクが複数の同時サブタスクに分割され、メイン・タスクが続行される前にサブタスクが完了する必要があるケースがサポートされます。 StructuredTaskScope
を使用すると、構造化プログラミングの順次演算と同様に、同時演算の存続期間が「構文ブロック」によって制限されるようにできます。
基本操作
StructuredTaskScope
は、そのパブリック・コンストラクタのいずれかを使用して作成されます。 サブタスクを実行するスレッドを開始するfork
メソッド、すべてのサブタスクが終了するのを待機するjoin
メソッド、およびタスク・スコープをクローズするclose
メソッドを定義します。 APIは、 try-with-resources
文で使用することを目的としています。 この意図は、try blockのコードがfork
メソッドを使用してスレッドをフォークしてサブタスクを実行し、join
メソッドでサブタスクが終了するまで待機し、「結果を処理」を使用することです。 fork
メソッドをコールすると、「フォークされたサブタスク」を表すSubtask
PREVIEWが返されます。 join
がコールされると、Subtask
を使用して、結果が正常に完了したり、サブタスクが失敗した場合は例外を取得できます。
Callable<String> task1 = ...
Callable<Integer> task2 = ...
try (var scope = new StructuredTaskScope<Object>()) {
Subtask<String> subtask1 = scope.fork(task1);
Subtask<Integer> subtask2 = scope.fork(task2);
scope.join();
... process results/exceptions ...
} // close
次の例では、同種のサブタスクのコレクションをフォークし、すべてのサブタスクがjoin
メソッドで完了するのを待機し、Subtask.State
PREVIEWを使用して、正常に完了したサブタスクのセットと、失敗したサブタスクの別のサブタスクにサブタスクをパーティション化します。
List<Callable<String>> callables = ...
try (var scope = new StructuredTaskScope<String>()) {
List<Subtask<String>> subtasks = callables.stream().map(scope::fork).toList();
scope.join();
Map<Boolean, Set<Subtask<String>>> map = subtasks.stream()
.collect(Collectors.partitioningBy(h -> h.state() == Subtask.State.SUCCESS,
Collectors.toSet()));
} // close
正しい使用を確実にするために、join
およびclose
メソッドはowner (タスク・スコープを開いたり作成したスレッド)によってのみ起動でき、所有者がフォーク後にjoin
メソッドを呼び出さなかった場合、close
メソッドはクローズ後に例外をスローします。
StructuredTaskScope
は、タスク・スコープを閉じずに停止するshutdown
メソッドを定義します。 shutdown()
メソッド「取消」は、すべての未完了サブタスクを「割り込み」によってスレッドに指定します。 新しいスレッドがタスク・スコープで開始されないようにします。 所有者がjoin
メソッドで待機している場合は、ウェイクアップします。
シャットダウンはshort-circuitingに使用され、すべてのサブタスクの完了を必要としない「政策」をサブクラスに実装できます。
一般的なケースのポリシーを持つサブクラス
StructuredTaskScope
の2つのサブクラスは、一般的な場合にポリシーを実装するために定義されています:
-
ShutdownOnSuccess
PREVIEWは、正常に完了する最初のサブタスクの結果を取得します。 取得すると、タスク・スコープがシャットダウンされ、未完了のスレッドが中断され、所有者がウェイクアップされます。 このクラスは、サブタスクの結果が("任意の起動")を実行し、他の未完了サブタスクの結果を待機する必要がない場合に対象となります。 最初の結果を取得するメソッド、またはすべてのサブタスクが失敗した場合に例外をスローするメソッドを定義します。 -
ShutdownOnFailure
PREVIEWは、失敗する最初のサブタスクの例外を取得します。 取得すると、タスク・スコープがシャットダウンされ、未完了のスレッドが中断され、所有者がウェイクアップされます。 このクラスは、すべてのサブタスクの結果が("すべて起動")を必要とする場合を対象としています。サブタスクが失敗した場合、他の未完了サブタスクの結果は不要になります。 サブタスクのいずれかが失敗した場合に例外をスローするメソッドを定義する場合。
次に、2つのクラスを使用する2つの例を示します。 どちらの場合も、2つのURLのロケーション"left"および"right"からリソースをフェッチするために、サブタスクのペアがフォークされます。 最初の例では、最初のサブタスクが正常に完了する結果を取得するShutdownOnSuccessオブジェクトを作成し、タスク・スコープを停止することによってもう一方を取消しします。 サブタスクのいずれかが結果で完了するか、両方のサブタスクが失敗するまで、メイン・タスクはjoin
で待機します。 result(Function)
PREVIEWメソッドを起動して、取得された結果を取得します。 両方のサブタスクが失敗した場合、このメソッドは、原因としていずれかのサブタスクから例外とともに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)
PREVIEWを起動して、いずれかのサブタスクが失敗した場合に例外をスローします。 両方のサブタスクが正常に完了した場合、このメソッドはno-opです。 この例では、Supplier.get()
を使用して各サブタスクの結果を取得します。 一般的に、forkによって返されるオブジェクトが、正常に完了したサブタスクの結果を取得するためにのみ使用される場合には、Subtask
のかわりにSupplier
を使用することをお薦めします。
Instant deadline = ...
try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
Supplier<String> supplier1 = scope.fork(() -> query(left));
Supplier<String> supplier2 = scope.fork(() -> query(right));
scope.joinUntil(deadline);
scope.throwIfFailed
(e -> new WebApplicationException(e));
// both subtasks completed successfully
String result = Stream.of(supplier1, supplier2)
.map(Supplier::get)
.collect(Collectors.joining(", ", "{ ", " }"));
...
}
StructuredTaskScopeの拡張
StructuredTaskScope
を拡張し、handleComplete
メソッドをオーバーライドして、ShutdownOnSuccess
およびShutdownOnFailure
によって実装されたポリシー以外のポリシーを実装できます。 たとえば、サブクラスは、正常に完了したサブタスクの結果を収集し、失敗したサブタスクを無視する場合があります。 サブタスクが失敗した場合に例外が収集される場合があります。 shutdown
メソッドを起動して停止し、一部の条件が発生したときにjoin
がウェイクアップする場合があります。
サブクラスは、通常、join
メソッドの後に実行されるコードに対して使用可能な結果、状態またはその他の結果を作成するメソッドを定義します。 結果を収集し、失敗したサブタスクを無視するサブクラスでは、結果を返すメソッドを定義できます。 サブタスクが失敗したときに停止するポリシーを実装するサブクラスは、失敗する最初のサブタスクの例外を取得するメソッドを定義できます。
次に、正常に完了した同種のサブタスクを収集する単純なStructuredTaskScope
実装の例を示します。 メイン・タスクが結合後に起動できるメソッド"completedSuccessfully()
"を定義します。
class CollectingScope<T> extends StructuredTaskScope<T> {
private final Queue<Subtask<? extends T>> subtasks = new LinkedTransferQueue<>();
@Override
protected void handleComplete(Subtask<? extends T> subtask) {
if (subtask.state() == Subtask.State.SUCCESS) {
subtasks.add(subtask);
}
}
@Override
public CollectingScope<T> join() throws InterruptedException {
super.join();
return this;
}
public Stream<Subtask<? extends T>> completedSuccessfully() {
super.ensureOwnerAndJoined
();
return subtasks.stream();
}
}
この例のcompletedSuccessfully()
メソッドの実装では、ensureOwnerAndJoined()
を起動して、メソッドが結合された後にのみ所有者スレッドによってのみ呼び出されるようにします。
ツリー構造
タスク・スコープは、新しいタスク・スコープを開いたときに親子関係が暗黙的に確立されるツリーを形成します:- 親子関係は、タスク・スコープで開始されたスレッドが独自のタスク・スコープを開くと確立されます。 タスク・スコープ"A"で開始されたスレッドで、タスク・スコープ"B"を開くと、タスク・スコープ"A"がタスク・スコープ"B"の親である親子関係が確立されます。
- 親子関係はネストによって確立されます。 スレッドがタスク・スコープ"B"を開き、タスク・スコープ"C" ("B"をクローズする前に)を開くと、包含タスク・スコープ"B"はネストされたタスク・スコープ"C"の親になります。
ツリー構造は次のものをサポートします:
- スレッド間での「スコープ値」PREVIEWの継承。
- 確認チェック。 メソッド記述の"タスク範囲に含まれるスレッド"というフレーズは、タスク・スコープまたは子孫スコープで開始されたスレッドを意味します。
次の例は、スコープ値の継承を示しています。 スコープ値USERNAME
は、値"duke
"にバインドされます。 StructuredTaskScope
が作成され、 childTask
を実行するスレッドを起動するためにそのfork
メソッドが起動されます。 スレッドは、タスク・スコープの作成時に取得されたスコープ値「バインド」を継承します。 childTask
のコードは、スコープ値の値を使用するため、値"duke
"を読み取ります。
private static final ScopedValue<String> USERNAME = ScopedValue.newInstance();
ScopedValue.runWhere
(USERNAME, "duke", () -> {
try (var scope = new StructuredTaskScope<String>()) {
scope.fork(() -> childTask());
...
}
});
...
String childTask() {
String name = USERNAME.get
(); // "duke"
...
}
StructuredTaskScope
では、現時点ではツリー構造を公開するAPIは定義されません。
特に指定しないかぎり、このクラスのコンストラクタまたはメソッドにnull
引数を渡すと、NullPointerException
がスローされます。
メモリーの一貫性の影響
サブタスクhappen-beforeの「フォーク」より前のタスク・スコープの所有者スレッドまたは含まれるスレッドでのアクション。このサブタスクによって実行されるアクションは、happen-beforeで、サブタスクの結果は「取得済」PREVIEWまたはhappen-beforeで、タスク・スコープのjoiningの後にスレッドで実行されるアクションです。
- Java言語仕様を参照してください:
-
17.4.5 Happens-beforeオーダー
- 導入されたバージョン:
- 21
-
ネストされたクラスのサマリー
修飾子と型クラス説明static final class
static final class
Preview.「successfully」PREVIEWに完了する最初のサブタスクの結果を取得するStructuredTaskScope
。static interface
Preview.fork(Callable)
でフォークされたサブタスクを表します。 -
コンストラクタのサマリー
コンストラクタ説明仮想スレッドを作成する名前のない構造化タスク・スコープを作成します。StructuredTaskScope
(String name, ThreadFactory factory) 指定された名前とスレッド・ファクトリを使用して構造化タスク・スコープを作成します。 -
メソッドのサマリー
修飾子と型メソッド説明void
close()
このタスク範囲を閉じます。protected final void
現在のスレッドがこのタスク・スコープの所有者であること、および「フォーク」サブタスクの後に(join()
またはjoinUntil(Instant)
)を結合したことを確認します。<U extends T>
StructuredTaskScope.SubtaskPREVIEW<U> このタスク・スコープで新しいスレッドを開始して、値を戻すタスクを実行し、このタスク・スコープの「サブタスク」を作成します。protected void
handleComplete
(StructuredTaskScope.SubtaskPREVIEW<? extends T> subtask) このタスク・スコープで正常に完了または失敗したときに、サブタスクによって起動されます。final boolean
このタスク・スコープがシャットダウンされている場合はtrueを返し、それ以外の場合はfalseを返します。join()
このタスク・スコープで開始されたすべてのサブタスクが終了するか、タスク・スコープが停止するまで待機します。このタスク・スコープで開始されたすべてのサブタスクが終了するまで、またはタスク・スコープが停止するまで、指定した期限まで待機します。void
shutdown()
このタスク・スコープをクローズせずに停止します。
-
コンストラクタの詳細
-
StructuredTaskScope
public StructuredTaskScope(String name, ThreadFactory factory) 指定された名前とスレッド・ファクトリを使用して構造化タスク・スコープを作成します。 タスク範囲には、モニタリングおよび管理の目的で任意の名前が付けられます。 スレッド・ファクトリは、サブタスクが「フォーク」の場合にcreate
スレッドに使用されます。 タスク・スコープは現在のスレッドによって所有されます。Constructionは、現在のスレッドの「スコープ値」PREVIEWバインディングを取得して、タスク・スコープで開始されたスレッドによる継承を取得します。 クラス説明の「ツリー構造」セクションには、スコープ値バインディングの継承を目的として、親子関係が暗黙的に確立される方法の詳細が示されています。
- パラメータ:
name
- タスク範囲の名前。NULLにできますfactory
- スレッドのファクトリ
-
StructuredTaskScope
public StructuredTaskScope()仮想スレッドを作成する名前のない構造化タスク・スコープを作成します。 タスク・スコープは現在のスレッドによって所有されます。- 実装要件:
- このコンストラクタは、
null
という名前の2引数コンストラクタと、仮想スレッドを作成するスレッド・ファクトリの起動と同等です。
-
-
メソッドの詳細
-
ensureOwnerAndJoined
protected final void ensureOwnerAndJoined()現在のスレッドがこのタスク・スコープの所有者であること、および「フォーク」サブタスクの後に(join()
またはjoinUntil(Instant)
)を結合したことを確認します。- APIのノート:
- このメソッドは、結合メソッドの後に実行するコードに対して、使用可能な結果、状態またはその他の結果を生成するメソッドを定義するサブクラスで使用できます。
- 例外:
WrongThreadException
- 現在のスレッドがタスク・スコープ所有者でない場合IllegalStateException
- タスク・スコープがオープンで、タスク・スコープ所有者がフォーク後に結合しなかった場合
-
handleComplete
protected void handleComplete(StructuredTaskScope.SubtaskPREVIEW<? extends T> subtask) このタスク・スコープで正常に完了または失敗したときに、サブタスクによって起動されます。 このメソッドは、タスク・スコープが「停止」の後にサブタスクが完了した場合には起動されません。- APIのノート:
handleComplete
メソッドはスレッド・セーフである必要があります。 複数のスレッドによって同時に起動できます。- 実装要件:
- サブタスクが
null
の場合、デフォルトの実装ではNullPointerException
がスローされます。 サブタスクが完了していない場合、IllegalArgumentException
がスローされます。 - パラメータ:
subtask
- サブタスク- 例外:
IllegalArgumentException
- 完了していないサブタスクでコールされた場合
-
fork
public <U extends T> StructuredTaskScope.SubtaskPREVIEW<U> fork(Callable<? extends U> task) このタスク・スコープで新しいスレッドを開始して、値を戻すタスクを実行し、このタスク・スコープの「サブタスク」を作成します。値を返すタスクは、このメソッドに
Callable
として提供され、スレッドはタスクのcall
メソッドを実行します。 スレッドは、タスク・スコープのThreadFactory
を使用して作成されます。 現在のスレッドの「スコープ値」PREVIEWバインディングを継承します。 バインディングは、タスク・スコープの作成時に取得されたバインディングと一致する必要があります。このメソッドは、「フォークされたサブタスク」を表す
Subtask
PREVIEWを返します。Subtask
オブジェクトを使用すると、サブタスクが正常に完了したとき、またはサブタスクが失敗したときの例外を取得できます。 正しい使用を確実にするために、get()
PREVIEWおよびexception()
PREVIEWメソッドは、すべてのスレッドがjoin
またはjoinUntil(Instant)
メソッドで終了するまで待機した後でのみ、タスク・スコープ所有者によってコールできます。 サブタスクが完了すると、スレッドはhandleComplete
メソッドを呼び出して、完了したサブタスクを消費します。 サブタスクが完了する前にタスク・スコープが「停止」の場合、handleComplete
メソッドは起動されません。このタスク・スコープがshutdown (またはシャットダウン処理中)の場合、サブタスクは実行されず、
handleComplete
メソッドは起動されません。このメソッドは、タスク・スコープ所有者またはタスク・スコープに含まれるスレッドによってのみ起動できます。
- 実装要件:
- このメソッドは、たとえばラップ・タスクなど、カスタマイズの目的でオーバーライドできます。 オーバーライドされた場合、サブクラスは
super.fork
を呼び出して、このタスク・スコープで新しいスレッドを開始する必要があります。 - 型パラメータ:
U
- 結果の型- パラメータ:
task
- 実行するスレッドの値を返すタスク- 戻り値:
- サブタスク
- 例外:
IllegalStateException
- このタスク範囲がクローズされている場合WrongThreadException
- 現在のスレッドがタスク・スコープの所有者またはタスク・スコープに含まれるスレッドでない場合StructureViolationExceptionPREVIEW
- 現在のスコープ値バインディングがタスク・スコープが作成されたときと同じでない場合RejectedExecutionException
- スレッド・ファクトリがサブタスクを実行するスレッドの作成を拒否した場合
-
join
public StructuredTaskScopePREVIEW<T> join() throws InterruptedExceptionこのタスク・スコープで開始されたすべてのサブタスクが終了するか、タスク・スコープが停止するまで待機します。このメソッドは、このタスク・スコープのすべてのスレッドstartedが実行の完了を待機して、すべてのサブタスクを待機します。 すべてのスレッドが終了したとき、タスク・スコープが「停止」の場合、または現在のスレッドがinterruptedの場合、待機が停止します。
このメソッドは、タスク・スコープ所有者のみが起動できます。
- 実装要件:
- このメソッドは、カスタマイズの目的で上書きしたり、より具体的な戻りタイプを返すことができます。 オーバーライドされた場合、サブクラスは
super.join
を呼び出して、メソッドがこのタスク・スコープのスレッドが終了するまで待機する必要があります。 - 戻り値:
- このタスクの範囲
- 例外:
IllegalStateException
- このタスク範囲がクローズされている場合WrongThreadException
- 現在のスレッドがタスク・スコープ所有者でない場合InterruptedException
- 待機中に割込みが発生した場合
-
joinUntil
public StructuredTaskScopePREVIEW<T> joinUntil(Instant deadline) throws InterruptedException, TimeoutException このタスク・スコープで開始されたすべてのサブタスクが終了するまで、またはタスク・スコープが停止するまで、指定した期限まで待機します。このメソッドは、このタスク・スコープのすべてのスレッドstartedが実行の完了を待機して、すべてのサブタスクを待機します。 すべてのスレッドが終了するか、タスク・スコープが「停止」、期限に達するか、現在のスレッドがinterruptedになると、待機が停止します。
このメソッドは、タスク・スコープ所有者のみが起動できます。
- 実装要件:
- このメソッドは、カスタマイズの目的で上書きしたり、より具体的な戻りタイプを返すことができます。 オーバーライドされた場合、サブクラスは
super.joinUntil
を呼び出して、メソッドがこのタスク・スコープのスレッドが終了するまで待機する必要があります。 - パラメータ:
deadline
- 期限- 戻り値:
- このタスクの範囲
- 例外:
IllegalStateException
- このタスク範囲がクローズされている場合WrongThreadException
- 現在のスレッドがタスク・スコープ所有者でない場合InterruptedException
- 待機中に割込みが発生した場合TimeoutException
- 待機中に期限に達した場合
-
shutdown
public void shutdown()このタスク・スコープをクローズせずに停止します。 タスク・スコープを停止すると、新しいスレッドが開始され、すべての未完了スレッドが中断され、join
メソッドがウェイクアップされます。 シャットダウンは、未完了のサブタスクの結果が不要になった場合に役立ちます。 これは通常、結果に達した後、未完了のタスクを破棄するポリシーを実装するサブクラスのhandleComplete(Subtask)
実装によってコールされます。より具体的には、このメソッドは次のとおりです:
- タスク範囲(現在のスレッドを除く)のすべての未完了スレッドを「割り込み」します。
-
join()
またはjoinUntil(Instant)
で待機している場合、タスク・スコープの所有者を起動します。 タスク・スコープの所有者が待機していない場合、join
またはjoinUntil
への次のコールはすぐに返されます。
このメソッドは、タスク・スコープ所有者またはタスク・スコープに含まれるスレッドによってのみ起動できます。
- APIのノート:
- スレッド割り込みに (または迅速に応答)を応答しなかったコードを実行しているために、終了していないスレッドがある可能性があります。 このメソッドはこれらのスレッドを待機しません。 所有者が
close
メソッドを起動してタスク・スコープを閉じると、残りのスレッドが終了するまで待機します。 - 実装要件:
- このメソッドは、カスタマイズの目的で上書きできます。 オーバーライドされた場合、サブクラスは
super.shutdown
を起動して、メソッドがタスク・スコープを停止するようにする必要があります。 - 例外:
IllegalStateException
- このタスク範囲がクローズされている場合WrongThreadException
- 現在のスレッドがタスク・スコープの所有者またはタスク・スコープに含まれるスレッドでない場合- 関連項目:
-
isShutdown
public final boolean isShutdown()このタスク・スコープがシャットダウンされている場合はtrueを返し、それ以外の場合はfalseを返します。- 戻り値:
- このタスク・スコープが停止した場合はtrue、停止しない場合はfalse
- 関連項目:
-
close
public void close()このタスク範囲を閉じます。このメソッドは、最初にタスク範囲(
shutdown
メソッドを起動した場合と同じ)をシャットダウンします。 その後、未完了のタスクを実行するスレッドが終了するまで待機します。 中断された場合、このメソッドは、中断ステータスが設定された状態で完了するまで、スレッドが終了するまで待機し続けます。このメソッドは、タスク・スコープ所有者のみが起動できます。 タスク・スコープがすでにクローズされている場合、このメソッドを起動するタスク・スコープ所有者は無効です。
StructuredTaskScope
は、「構造化方式」で使用することを目的としています。 このメソッドが呼び出されて、ネストされたタスク・スコープがクローズされる前にタスク・スコープをクローズすると、ネストされた各タスク・スコープ(作成した逆の順序)の基礎となる構成がクローズされ、このタスク・スコープがクローズされて、StructureViolationException
PREVIEWがスローされます。 同様に、「スコープ値」PREVIEWバインディングで実行中にタスク・スコープを閉じるためにこのメソッドがコールされ、スコープ値がバインドされる前にタスク・スコープが作成された場合、タスク・スコープを閉じると、StructureViolationException
がスローされます。 スレッドが最初に所有するタスク・スコープを閉じることなく終了すると、終了によって、そのオープン・タスク・スコープの基礎となる構成がクローズされます。 クローズは、タスク範囲が作成された逆の順序で実行されます。 したがって、タスク・スコープの所有者が、これらのタスク・スコープでフォークされたスレッドが終了するまで待機する必要がある場合、スレッドの終了が遅延する可能性があります。- 定義:
close
、インタフェースAutoCloseable
- 実装要件:
- このメソッドは、カスタマイズの目的で上書きできます。 オーバーライドされた場合、サブクラスは
super.close
を呼び出してタスク・スコープを閉じる必要があります。 - 例外:
IllegalStateException
- タスク・スコープの所有者がフォーク後に結合を試行しなかった場合、タスク・スコープのクローズ後にスローされましたWrongThreadException
- 現在のスレッドがタスク・スコープ所有者でない場合StructureViolationExceptionPREVIEW
- 構造違反が検出された場合
-
StructuredTaskScope
を使用できます。