(そのようなファイルをダウンロードするなど)、非同期IO操作とタスク、および無関係の一連を行う場合、マルチスレッドが大幅に運用効率を向上させることができます。スレッドプールは、一連のスレッドが含まれており、これらのスレッドを管理することができます。例:スレッドを作成、スレッドが破壊されたというように。この記事では、プール内のJavaスレッドを使用してタスクを実行する方法について説明します。
1タスクタイプ
タスクを実行するスレッドプールを使用する前に、我々は、タスクはスレッドプールから呼び出すことができるかを把握します。タスクは、タスクは、2つのタイプ、すなわち、のRunnableタスククラスを達成するために、(NOパラメータは値を返さない)クラスインターフェースと実装呼び出し可能タスク(ノーリターン値パラメータ)に分けることができるかどうかに応じて値を返します。対応するコードを演奏するとジョブ要件の種類に応じて選択されます。
1.1のRunnableクラスを実装
マルチスレッドタスクのタイプ、自然最初に考えたが達成する のRunnable インタフェースクラスを、Runnableインタフェースが抽象メソッドの実行を提供し、この方法は、パラメータ、戻り値はありません。例えば:
Runnableをタスクが= 新しいRunnableを(){ @Override 公共 のボイドの実行(){ System.out.printlnは( "タスクを実行します。" ); } }。
またはJava 8以降シンプルな言葉遣い:
実行可能なタスク=() - > { するSystem.out.println( "タスクを実行します。" )。 }。
1.2呼び出し可能インターフェース・クラスを実装
同様のRunnableで呼び出し可能な唯一の抽象メソッドが、抽象メソッドは、値を返します。このインタフェースの実装時には、戻り値の型を開発する必要があります。例えば:
呼び出し可能<文字列> callableTask =() - > "完成"。
スレッドプールの2種類
java.util.concurrent.Executorsは、スレッドプールのさまざまなを作成するための静的メソッドのシリーズを提供します。スレッドプールと主な特徴のいくつかの次の例では、スレッドプールの他の特徴は、次のようにして誘導されたものを例示していません。
スレッドプール2.1固定スレッドプール内のスレッドの固定数
名前が示すように、スレッドプールのスレッド数のこのタイプは固定されています。実行中のほとんどのn個のスレッドで任意の時刻n、スレッドプールにスレッド数の場合。スレッドプールが飽和状態で実行する場合は、スレッドプールのタスクとし、さらに提出を実行キューに置かれます。スレッドプールが飽和状態にある場合は、スレッドプールはシャットダウンExecuteServiceメソッドが呼び出されるまで、スレッドプールがクリアされますが存在します。
// スレッドプール5内のスレッドの数を作成します。 ExecutorServiceのExecutorServiceの= Executors.newFixedThreadPool(5)。
スレッドプールにキャッシュされた2.2キャッシュできるスレッドプール
アイドルスレッドプールのスレッドが(0のスレッドもアイドルのスレッドを意味していない)が存在しない場合は、プールでの初期サイズが0であるスレッドプールスレッド、このタイプは、タスクを送信し続けるために、新しいスレッドをなしタスクことを確実にするために作成されます待って、アイドル状態のスレッドがある場合は、スレッドを実行するには、アイドルタスクを多重化します。スレッドが60秒間アイドル状態のみキャッシュされたスレッドプールのアイドル時間に達するの60年代のスレッドが閉じられ、スレッドプールから削除されますです。プロセスでは短命の数が多い:(公式声明は短命)とき非同期タスクは、重要なプロバイダのパフォーマンスを持つことができます。
// キャッシュされたスレッドプールを作成 ExecutorServiceのExecutorServiceの= Executors.newCachedThreadPool();
2.3シングルスレッドプール
それは、スレッド内にあるので、これは、スレッドプールと呼ばれないことがあり、常に一つだけ、そして唯一の始まりから終わりまでです(なぜあなたはしたいとするので、これを言う Executors.newFixedThreadPool(1) 」、彼らはまだそれを呼んで区別する)シングルスレッドのプール。」あなたは、単一のスレッド・プールの追加タスク過去に休むことができますが、それぞれの時間はわずか1を実行し、タスクが順次実行されます。前のタスクが異常があらわれた場合は、現在のスレッドが破壊されますが、新しいスレッドは後者のタスクを実行するために作成されます。これらの一方のみのスレッドがスレッドプールは、同じ固定スレッドの数。唯一の違いは、両方のことで、 Executors.newFixedThreadPool(1)は 、実行時にその内のスレッド数を変更することができますが、 Executors.newSingleThreadExecutor()が しかのスレッドを持つことができます。「なぜ」については、私は、ソースコードによって解析専用のブログを書くつもりです。
// 単一スレッドプールを作成 ExecutorServiceのExecutorServiceの= Executors.newSingleThreadExecutor()。
2.4作業は、スレッドプールを盗みます
ツメガエルのソースコードは、あなたは本質的に仕事がスレッドプールを盗むでしょう ForkJoinPool のタスクがCPUリソースを消費し、より多くの処理のために、スレッドプールのこのタイプのマルチコアCPUの処理タスクをフルに活用。これは、複数のタスクキューを維持するスレッドの固定数、ではありません、キュータスクが完了すると、対応するスレッドが他のタスクからタスク実行キューを盗む、それはまた、タスクの実行順序と秩序の始まりを意味し、同じを提出します。高い需要がある場合は、スレッドプールはForkJoinPoolから直接取得することができます。
// CPUコア数はCPUコア機の数に等しい、スレッドプールを盗む仕事を作成 ExecutorServiceのExecutorServiceの= Executors.newWorkStealingPool(); // CPUコアを使用して、作動スレッドプールの盗難を作成する3が計算され、作業がスレッドプールを盗むことができません。スレッドの数 ExecutorServiceのexecutorService2 = Executors.newWorkStealingPool(3)。
2.5スケジュールされたタスクのスレッドプール
スケジュールされたタスク・スレッド・プールには、例えば、計画に従って特定のタスクを実行できます。定期的にタスクを実行します。
// スケジュールされたタスクのスレッドプールのサイズを取得する2 ScheduledExecutorService ScheduledExecutorService = Executors.newScheduledThreadPool(2 );
// スレッド情報を印刷スケジュールされたタスクを追加し、タスクは3秒後に実行される scheduledExecutorService.schedule(() - > {システム.out.println(にThread.currentThread());}、3 、TimeUnit.SECONDS);
//は、タスクをスケジュールスレッド情報を印刷、5秒ごとに一度実行した後、2秒後に実行される最初の時間のためにタスクを追加します。タスクの実行時間が5秒を超えた場合、次回は、直前の実行完了後になり scheduledExecutorService.scheduleAtFixedRate(() - > {のSystem.out.println(にThread.currentThread());}、2、。5 、 TimeUnit.SECONDSは);
// 5秒ごとにタスクの実行後に、次の時間をスレッド情報を印刷スケジュールされたタスク、2秒後に実行される最初の時間のためのタスクを追加し、。 scheduledExecutorService.scheduleWithFixedDelay(() - > {のSystem.out.println(にThread.currentThread());}、2 ,. 5 、TimeUnit.SECONDS);
//クリアアイドル状態ごとのスレッド scheduledExecutorService.shutdown();
// ブロックされ、コードがスレッドプールの前にダウンして行くことはありませんが、閉じたチューンである scheduledExecutorService.awaitTermination(はLong.MAX_VALUE、TimeUnit.SECONDS)。
3タスクを実行するスレッドプールを使用します
先に述べたように、タスクの種類のタイプが戻り値と戻り値なしに分けられ、また戻り値を呼び出していないコールとリターンの値に分割して、ここで呼び出します。
3.1ノーリターンコール値タスク
値が呼び出したタスクに返却されていない場合は、両方この場合、本質的に同じで、メソッドを実行または提出することができます。タスクは団結を維持するために呼び出す任務に復帰するためには、推奨される方法を提出します。
// スレッドプールの作成 ExecutorServiceのExecutorServiceの= Executors.newFixedThreadPool(3 ); // 戻り値のないタスクに(実装、Runnableインタフェース)を提出 ExecutorService.submitを(() - >のSystem.out.println( "こんにちは")) ; executorService.shutdown(); executorService.awaitTermination(はLong.MAX_VALUEの、TimeUnit.SECONDS)。
タスクのセットがある場合は、一つ一つを提出することができます。
// スレッドプールを作成 ExecutorServiceのExecutorServiceの= Executors.newFixedThreadPool(3 ); リスト <Runnableを>タスク= は、Arrays.asList( () - >のSystem.out.println( "こんにちは" )、 () - > System.out.printlnは( "世界" )); // 個別に提出したタスク tasks.forEach(ExecutorServiceの提出::); executorService.shutdown(); executorService.awaitTermination(はLong.MAX_VALUE、TimeUnit.SECONDSを)。
3.2戻り値タスクの呼び出し
場所を指定し、一般的な戻り値の型に実装する場合、呼び出し可能インターフェースを実装するための値を返すタスク必要があります。あなたは提出メソッドを呼び出すと今後のオブジェクトを返し、(未来の方法を介して取得)の戻り値を取得することができます。あなたが得る()コードブロックを呼び出すときに、タスクが完了するまでは、戻り値があることに留意すべきです。
ExecutorServiceのExecutorServiceの= Executors.newFixedThreadPool(2 )。 将来の <文字列>未来= executorService.submit(() - > "こんにちは" ); System.out.println(future.isDone())。// falseの 文字列値= future.get(); System.out.println(future.isDone())。// 真 のSystem.out.println(値); // こんにちは
あなたはタスクの数を提出したい場合は、ほかにExecutorServiceのは、一つ一つを提出することができます、また、コールは1回を提出invokeAllすることができ、invokeAll内部実装は、実際には、サイクル・バイ・提出ジョブを使用しています。返さInvokeAll値は、今後の一覧です。
ExecutorServiceのExecutorServiceの= Executors.newFixedThreadPool(2 )。 一覧 <呼び出し可能<文字列>>タスク=は、Arrays.asList(() - > "こんにちは"、() - > "世界" ); 一覧 <今後の<string >>先物= executorService.invokeAll(タスク)。
invokeAny方法は、器具の数呼び出し可能なタスクを実行するための有用なスレッドプールされ、その後、他のタスクが適切に例外は存在しないキャンセルされないタスクを実行するために第1の値の終わりを返します。次のコードが出力されない「こんにちは」
ExecutorServiceのExecutorServiceの= Executors.newFixedThreadPool(2 )。 リスト <呼び出し可能<文字列>>タスク= は、Arrays.asList( () - > { のThread.sleep( 500L ) のSystem.out.println( "こんにちは" ); リターン "こんにちは" ; }、() - > { システム。 out.printlnを( "世界" ); リターン "世界" ; }); 文字列s = executorService.invokeAny(タスク)。 System.out.println(S); // 世界
出力:
世界
の世界
また、ソースを表示するときの方法が発見された提供ExecutorServiceの <T>将来<T>送信(Runnableをタスク、Tを結果) 、この方法は、タスクの実装、Runnableインタフェースを介して送信し、戻り値をすることができると、Runnableインタフェースを実行する方法の戻り値なし。戻り値は、それから来るということですか?実際には、問題が提出方法の後ろの引数は、このパラメータの値が返されることです。メソッドを提出呼び出した後、そこにパス操作で、その後、直接、結果パラメータを返します。
ExecutorServiceのExecutorServiceの= Executors.newFixedThreadPool(1 )。 将来の <文字列>未来= executorService.submit(() - >のSystem.out.println( "こんにちは")、 "世界" ); System.out.println(future.get())。// 输出:世界
4まとめ
マルチスレッド処理タスクを使用するときは、状況に応じてタスクとスレッドプールタイプの右の種類を選択する必要があります。戻り値なし場合は、タスク呼び出し可能か、Runnableインタフェースを達成するために使用することができ、戻り値は、呼び出し可能インターフェースのタスクを達成するために使用する必要がある場合、getメソッドの戻り値は、将来になります。スレッドプールの選択、唯一のスレッドによって、または固定容量1のシングルスレッドプールスレッドプールの容量であれば、いくつか、またはサイクルを実行する計画がある。ハンドル大型ショートライブタスクは、キャッシュされたスレッドプールを使用することですタスクは、あなたがスケジュールされたタスクのスレッドプールを使用することができます。タスクがCPUリソース、アプリケーション、ワークスチールスレッドプールを大量に消費する必要がある場合。