コンストラクタに aをExecutorService
渡すオーバーラン スレッドを使用する利点は何ですか?Runnable
Thread
9 に答える
ExecutorService
raw のような低レベルの抽象化に関連する複雑さの多くを抽象化しThread
ます。タスクの正常終了時または突然の終了時に安全に開始、終了、サブミット、実行、およびブロックするためのメカニズムを提供します (Runnable
またはとして表されCallable
ます)。
JCiPのセクション 6.2 から、馬の口から直接:
Executor
単純なインターフェイスかもしれませんが、さまざまなタスク実行ポリシーをサポートする非同期タスク実行のための柔軟で強力なフレームワークの基礎を形成します。これは、タスクのサブミットをタスクの実行から分離する標準的な手段を提供し、タスクを として記述しRunnable
ます。実装はExecutor
、統計収集、アプリケーション管理、および監視を追加するためのライフサイクル サポートとフックも提供します。... を使用することExecutor
は、通常、アプリケーションにプロデューサー/コンシューマー デザインを実装するための最も簡単な方法です。
フレームワークを使用すると、並列処理の基礎となるインフラストラクチャの実装に (多くの場合、誤って、多大な労力をかけて) 時間を費やすのではなく、j.u.concurrent
タスク、依存関係、潜在的な並列処理の構造化に集中できます。同時実行アプリケーションの大規模な範囲では、タスク境界を特定して活用し、を利用するのは簡単です。これによりj.u.c
、より専門的なソリューションが必要になる可能性がある、真の同時実行の課題のはるかに小さなサブセットに集中できます。
また、ボイラープレートのルック アンド フィールにもかかわらず、同時実行ユーティリティをまとめた Oracle API ページには、それらを使用するための非常に確固たる議論が含まれています。
開発者は標準ライブラリ クラスをすでに理解している可能性が高いため、アドホックな同時実行コンポーネントの API と動作を学習する必要はありません。さらに、並行アプリケーションは、信頼性が高く十分にテストされたコンポーネント上に構築されている場合、デバッグがはるかに簡単になります。
SO に関するこの質問は、すぐに答えが JCiP である良い本について尋ねます。まだ持っていない場合は、自分でコピーを入手してください。そこに示されている並行性への包括的なアプローチは、この問題をはるかに超えており、長期的には多くの心痛を軽減します。
私が見る利点は、複数のスレッドを管理/スケジュールすることです。ExecutorService を使用すると、バグに悩まされる可能性のある独自のスレッド マネージャーを作成する必要がなくなります。これは、プログラムが一度に複数のスレッドを実行する必要がある場合に特に便利です。たとえば、一度に 2 つのスレッドを実行したい場合、次のように簡単に実行できます。
ExecutorService exec = Executors.newFixedThreadPool(2);
exec.execute(new Runnable() {
public void run() {
System.out.println("Hello world");
}
});
exec.shutdown();
この例は些細なことかもしれませんが、「hello world」行は負荷の高い操作で構成されており、プログラムのパフォーマンスを向上させるために、その操作を一度に複数のスレッドで実行する必要があると考えてみてください。これは一例にすぎません。複数のスレッドをスケジュールまたは実行し、ExecutorService をスレッド マネージャーとして使用したい場合はまだ多くあります。
単一のスレッドを実行する場合、ExecutorService を使用する明らかな利点はありません。
以下にいくつかの利点を示します。
- Executor サービスはスレッドを非同期的に管理します
- スレッドの完了後に返される結果を取得するには、Future callable を使用します。
- 解放されたスレッドへの作業の割り当てを管理し、完了した作業をスレッドから再販して新しい作業を自動的に割り当てる
- fork - 並列処理のためのフレームワークに参加する
- スレッド間の通信の改善
- invokeAll と invokeAny は、任意またはすべてのスレッドを一度に実行するためのより詳細な制御を提供します
- shutdown は、スレッドに割り当てられたすべての作業を完了する機能を提供します
- Scheduled Executor サービスは、実行可能オブジェクトと呼び出し可能オブジェクトの繰り返し呼び出しを生成するためのメソッドを提供します
ExecutorService は、FutureTask へのアクセスも提供します。FutureTask は、完了したバックグラウンド タスクの結果を呼び出し元のクラスに返します。Callableを実装する場合
public class TaskOne implements Callable<String> {
@Override
public String call() throws Exception {
String message = "Task One here. . .";
return message;
}
}
public class TaskTwo implements Callable<String> {
@Override
public String call() throws Exception {
String message = "Task Two here . . . ";
return message;
}
}
// from the calling class
ExecutorService service = Executors.newFixedThreadPool(2);
// set of Callable types
Set<Callable<String>>callables = new HashSet<Callable<String>>();
// add tasks to Set
callables.add(new TaskOne());
callables.add(new TaskTwo());
// list of Future<String> types stores the result of invokeAll()
List<Future<String>>futures = service.invokeAll(callables);
// iterate through the list and print results from get();
for(Future<String>future : futures) {
System.out.println(future.get());
}
Java 1.5 バージョンより前のバージョンでは、Thread/Runnable は 2 つの別個のサービス用に設計されていました。
- 仕事の単位
- その作業単位の実行
ExecutorService は、Runnable/Callable を作業単位として指定し、Executor を (ライフサイクルを使用して) 作業単位を実行するメカニズムとして指定することにより、これら 2 つのサービスを分離します。