public interface RunnableFuture<V> extends Runnable, Future<V> {
void run();
}
public class FutureTask<V> implements RunnableFuture<V> {
public FutureTask(Callable<V> callable) {
if (callable == null)
throw new NullPointerException();
this.callable = callable;
// ...
}
public FutureTask(Runnable runnable, V result) {
this.callable = Executors.callable(runnable, result);
// ...
}
}
コンストラクターから、FutureTaskはCallableタスクまたはRunnableタスクのいずれかをラップできることがわかりますが、最終的には常にRunnableからCallableタスクへの変換であり、実際には適応プロセスです。
上記の分析を通じて、Future全体が実際には3つのコアコンポーネントで構成されていることがわかります。
- 実際のタスク/データ型(通常、タスクの実行が遅いか、データの構築に時間がかかります)。
- Futureインターフェイス(呼び出し元は資格情報を使用して実際のタスク/データの結果を取得します)、つまりFutureインターフェイス。
- Future実装クラス(実際のタスク/データをラップするために使用)、つまりFutureTask実装クラス。
JUCが提供するFutureモードでは、最も重要なのはFutureTaskクラスです。FutureTaskはJDK1.5のときにJUCで導入されました。これは非同期タスクを表します。このタスクは通常、実行のためにExecutorに送信され、もちろん呼び出すこともできます。パーティはrunメソッドを直接呼び出して実行します。
「TheArtof Java Concurrent Programming」という本の中で、著者はFutureTask.run()メソッドの実行のタイミングに従ってFutureTaskを3つの状態に分割しています。
- 開始されていません。FutureTask.run()メソッドが実行される前は、FutureTaskは未開始の状態です。FutureTaskが作成されると、FutureTask.run()メソッドが実行される前にFutureTaskが開始されません。
- 有効化されました。FutureTask.run()メソッドの実行中、FutureTaskは開始状態にあります。
- 完了しました。FutureTask.run()メソッドの実行が終了するか、FutureTask.cancel(...)メソッドが呼び出されてタスクがキャンセルされるか、タスクの実行中に例外がスローされます。これらの状況は、FutureTaskの完了状態と呼ばれます。 。
次の図は、FutureTaskの状態変更プロセスをまとめたものです。
FutureTaskにはこれらの3つの状態があるため、FutureTaskのgetメソッドとcancelメソッドを実行した結果も、状態によって大きく異なります。getメソッドとcancelメソッドの概要は次のとおりです。
getメソッド:
- FutureTaskが開始または開始されていない場合、FutureTask.get ()メソッドを実行すると、呼び出し元のスレッドがブロックされます。
- FutureTaskが完了状態にある場合、FutureTask.get()メソッドを呼び出すと、呼び出し元のスレッドが結果をすぐに返すか、例外をスローします。
キャンセル方法:
- FutureTaskが開始されていない場合は、FutureTask.cancel()メソッドを実行すると、このタスクは実行されません。
- FutureTaskが開始状態のときに、FutureTask.cancel(true)メソッドを実行してスレッドを中断し、タスクを停止して続行します。FutureTask.cancel(false)を実行しても、タスクを実行しているスレッドには影響しません。
- ときFutureTaskがある中で完成した状態FutureTask.cancelを実行し、(...)メソッドがしますfalseを返します。
次の図を使用して、Futureのget()メソッドとcancel()メソッドを要約します。
Futureインターフェースに加えて、FutureTaskはRunnableインターフェースも実装します。
したがって、FutureTaskを実行のためにExecutorに渡すことも、呼び出し元のスレッド(FutureTask.run())によって直接実行することもできます。
さらに、FutureTaskの取得では、ExecutorService.submit()メソッドを介して、次にFutureTask.get()またはFutureTask.cancelメソッドを介してFutureTaskオブジェクトを返すこともできます。
アプリケーションシナリオ:スレッドが実行を継続する前に別のスレッドがタスクを実行するのを待つ必要がある場合、この時点でFutureTaskを使用できます。複数のタスクを実行する複数のスレッドがあり、各タスクは最大で1回しか実行できないとします。複数のスレッドが同じタスクを実行しようとすると、1つのスレッドのみがタスクを実行でき、他のスレッドはタスクが実行されるのを待ってから続行する必要があります。
参照:あなたは_ Great God、「The Art of JavaConcurrentProgramming」を聴いています