1.なぜ、スレッドプールを使用します
これは、タスクに提出スレッドプールの作業を行っデカップル戦略を提供し、いくつかの利点があります
リソースの利用率を向上させる
スレッドの作成とスレッドの破壊のオーバーヘッドを減らすために、独自のスレッドを再利用すること。
スレッドプールを使用し、単語の新しいスレッドを作成するために、各タスクのシステムリソースの無駄であるかどうません。スレッドを作成し、破壊するためのスレッドがシステムリソースの動作を消費しています。過度のスレッドに加えて、JVMのOutOfMemory発生する表示されます
応答時間の改善
、新しいタスクは、アイドル状態のスレッドがある場合は、スレッドを作成するプロセスの途中を保存、すぐにタスクを実行することができます
統一された管理スレッドは、
スレッドプールを管理していない場合は、しかし、場合にのみ、スレッドはシステムリソースが無制限に消費を作成するだけでなく、システムが不安定になりますさ。使用スレッドプールは、配布、チューニングや監視を統一することができます。
2.一般的なスレッドプールとパラメータ
2.1スレッドプールを作成します
このようなスレッドプール内のスレッドの固定された数を生成するように、エグゼキュータファクトリメソッドによってスレッドプールを作成します
ExecutorService executorService = Executors.newFixedThreadPool(5);
复制代码
ThreadPoolExecutorのコンストラクタでスレッドプールを作成するには
ThreadPoolExecutor pool = new ThreadPoolExecutor(int corePoolSize,
int maxmumPoolSize,
long keepAliveTime,
TimeUnit unit,
BolockingQueue<Runnable> workQueue,
ThreadFactory factory,
RejectedExecusionHandler handler);
复制代码
カスタム設定だけでなく、設定パラメータを選択する柔軟性あるため、後者を使用することをお勧めし、コンペア公式
ThreadPoolExecutorの内部コンストラクタによって達成されたスレッドプールを、作成するために、その方法を使用するかどうか。だから、完全にスレッド・プールの様々な特徴および特性を把握するために、それはようにと協力し、方法のパラメータ間の有意性の様々なパラメータを含むThreadPoolExecutorカテゴリの深い理解が必要です。
2.2スレッドプールのパラメータ
-
corePoolSizeカーネルスレッドの数。あなたは(タイムリーかつアイドルスレッドが存在する中で)タスクは、新しいスレッドプールのスレッドプールを作成し、提出する際、デフォルトで、基本サイズに等しいスレッドの数まで(あなたはまた、スレッドを事前に初期化することができます)
-
ワークキューに一時的に実行されるのを待って、ブロッキングキューに格納され、スレッドプール内の基本的なスレッドは、すべての時間ビジー状態であるとき、キューをブロックして、新しいタスクを送信する店舗タスク、一般的に使用されるのブロッキングキューについて、いくつかのがあります
- FIFOキューアレイながらブロッキング基づいArrayBlockingQueue(有限の長さ)
- LinkedBlockingQueueは(無限の長さの)ベースのFIFOブロッキングキューリストを実装しました
- SynchronousQueueタスク自体は、タスクがあるとき、保存されていない実行するスレッドまでブロックします
- 優先順位を持つPriorityBlockingQueueプライオリティキュー
-
maximumPoolSizeスレッドの最大数。コアスレッドのすべてが、その後もいくつかを実行するために追加のスレッドが作成され、キューがいっぱいのこのすべての時間を実行してブロックしている場合は、スレッドの数は、スレッドプールは、スレッドの最大数です。スレッドプールは、このアンバウンド形式のキューLinkedBlockingQueueとして使用されている場合、このパラメータには、役割を果たしています
-
KeepAliveTimeのとTimeUnitでスレッドアイドル時間がKeepAliveTimeの時間よりも大きい場合には、リサイクル可能とマークされ、プール内のスレッドの現在の数は、それが終了するカーネルスレッドの数よりも大きいです。だから、アンバウンド形式のキューを使用した場合と同じmaximumPoolSizeを持つこのパラメータは、動作しない、TimeUnitでは、時間の単位であります
-
RejectedExecusionHandler飽和戦略。私たちのタスクキューがいっぱいになった場合、およびスレッドプール内のスレッドの数はスレッドの最大数に達していない、とこれらのスレッドは、もはやアイドル状態です。今回は、その後、実行しないように、新しいタスクを送信するので、飽和戦略の必要性が来て、これらのタスクを扱います。Javaは一瞬いくつかの戦略を提供します
- AbortPolicy(デフォルトポリシー)直接スロー例外は、呼び出し側は、自分のニーズに応じて異常処理をキャプチャする必要があります
- DiscardPolicyは直接破棄タスクが処理されず、直接捨て
- 捨てDiscardOldestPolicy最近のタスクをキューイングし、現在のタスクを実行します。プライオリティキューは、その後、最も優先度の高いタスクを破棄する場合は、プライオリティキューと組み合わせて使用することは推奨されません
- 呼び出し元の現在のスレッドでこのタスクを実行するには、CallerRunsPolicy。
2.3共通のスレッドプール
Javaクラス・ライブラリは、スレッド・プールを作成する柔軟な方法を提供し、あなたはstaticファクトリメソッドエグゼキューを呼び出すことにより、スレッドプールを作成することができます。
- newFixedThreadPoolはあなたがスレッドを作成するためのタスクを送信するたびに、スレッドプール内のスレッドの固定数を作成します。プール内のスレッドの最大数まで。corePoolSizeとmaximumPoolSizeの値は同じであり、LinkedBlockingQueueを使用するため、スレッドプール、飽和戦略、生存時間などのパラメータの最大数は、使用されません。
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
复制代码
- newSingleThreadExecutor上記newFixedThreadPoolと類似しているスレッドが、執行は、唯一の違いは、ワーカースレッドです。唯一のワーカースレッドので、整然としたスレッドプールのタスク実行キューによって確保できるので、チームのためには、実行することです。
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
复制代码
- newCachedThreadPoolこのスレッドプール内のスレッドの数にInteger.MAX_VALUEに明示的な制限はデフォルトではありません、あなたがに対処するためのタスクごとにスレッドを作成することができますが、それはそうしませんでした、それはキャッシュスレッドの機能はスケーラブルです。たとえば、新しいタスクを処理するときには、新しく作成されていない場合は、処理するために利用可能なアイドル状態のスレッドが存在しない場合は最初に確認することです。スレッドは一定期間アイドル状態のときと(デフォルトは1分で)回復を作成します。
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
复制代码
- newScheduledThreadPool
タイミングを遅延させる、または行うことようにスレッドプール内のスレッドの固定数を作成し、。
public ScheduledThreadPoolExecutor(int corePoolSize) {
super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
new DelayedWorkQueue());
}
复制代码
3.実装プロセス
ミッションは、(java8)次のタスク処理を実行するために実行するエグゼキュータ・インターフェース()メソッドによって、スレッドプールを実行し、コアコードの一部を見ています
public void execute(Runnable command) {
int c = ctl.get();
if (workerCountOf(c) < corePoolSize) {
if (addWorker(command, true))
return;
c = ctl.get();
}
if (isRunning(c) && workQueue.offer(command)) {
int recheck = ctl.get();
if (! isRunning(recheck) && remove(command))
reject(command);
else if (workerCountOf(recheck) == 0)
addWorker(null, false);
}
else if (!addWorker(command, false))
reject(command);
}
复制代码
実行フロースレッドプールは(各スレッドプールはわずかに異なる達成するが、核となるアイデアは、同様である)は、以下の工程によって完成されます
1)まず、スレッドの数は、現在のスレッドのコア数よりも少ない作業している場合、実行するための新しいスレッドを作成します。スレッドプールのコア数がいっぱいの場合、
2)、その後、フルでない場合は、タスクキューにタスクを入れ、コアスレッドを運ぶために待ってアイドル状態で、スレッドプールのタスクキューがいっぱいになっているかを決定完全な場合は、次のステージに移動します
3)来て行う新しいスレッドを作成しない場合、最大の仕事は、スレッドの最大数に達したかどうかを判断するためにスレッドプール内のスレッドの数を決定します。それ以外の場合は、飽和戦略の使用はに対処します
あなたが実装されていれば見に行った場合は、内部では、各ワーカースレッドプールが労働者にパッケージ化され、タスクを実行するタスクをパッケージに実行されることがわかります。
4.ヘルスチェック
スレッドプールを監視する必要があるときに、プロジェクトにスレッドプールを使用しますので、あなたはすぐにスレッドプールの可用性に応じて問題を見つけることができます。提供スレッドプールのパラメータを経由して監視することができ、あなたは監視スレッド・プールに次のプロパティを使用することができます。
- あなたはtaskCountスレッドプールを実行する必要があるタスクの数
- completedTaskCountタスクが正常に数を実行されています
- スレッドの最大数はlargestPoolSize登場しています
- getPoolSizeは、スレッドの数を取得します
- アクティブなスレッドの数getActiveCount
サンプルコード
public class Task implements Runnable{
private int i;
public Task(int i) {
this.i = i;
}
@Override
public void run() {
System.out.println("task num ="+i);
}
}
复制代码
public class Test {
public static void main(String[] args) {
ThreadPoolExecutor pool = new ThreadPoolExecutor(10,20,60,TimeUnit.SECONDS,new ArrayBlockingQueue<>(5));
for (int i=0;i<5;i++){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("完成任务数= "+pool.getCompletedTaskCount()+" 任务数= "+pool.getTaskCount()+" " +
""+" 活动线程数="+pool.getActiveCount() +"" +" 线程数="+pool.getPoolSize() +" "+" 最大线程数="+pool.getLargestPoolSize() );
Task task = new Task(i);
pool.execute(task);
}
pool.shutdown();
}
}
复制代码
次のように印刷結果は以下のとおりです。
完成任务数= 0 任务数= 0 活动线程数=0 线程数=0 最大线程数=0
task num =0
完成任务数= 1 任务数= 1 活动线程数=0 线程数=1 最大线程数=1
task num =1
完成任务数= 2 任务数= 2 活动线程数=0 线程数=2 最大线程数=2
task num =2
完成任务数= 3 任务数= 3 活动线程数=0 线程数=3 最大线程数=3
task num =3
完成任务数= 4 任务数= 4 活动线程数=0 线程数=4 最大线程数=4
task num =4
复制代码