記事のディレクトリ
スレッドプールのアーキテクチャ
図は、スレッドプールの概略図です。トップレベルインターフェース内のJavaスレッドプールは、執行、執行しないスレッドであります
プールが、実行ツールの一つのスレッドのみ。実際のスレッドプールインタフェースはExecutorServiceのです。
より重要なカテゴリー:
クラス/インタフェース | 説明 |
---|---|
ExecutorServiceの | 実際のスレッドプールインターフェース |
ScheduledExecutorService | エネルギーと繰り返し実行が必要なタイマ/ TimerTaskを類似し、問題解決のためのタスク |
ThreadPoolExecutor | デフォルトの実装のExecutorServiceの |
ScheduledThreadPoolExecutor | ScheduledExecutorServiceインターフェースの継承ThreadPoolExecutor、定期的なタスクスケジューリングクラスの実装 |
スレッドプールは、より複雑で設定するには、特にスレッドプールの原理は非常に明確ではありません下のために、スレッドプールの可能性が高いの構成は、このように一般的に使用されるいくつかを生成し、いくつかの静的なファクトリエグゼキュークラスを提供し、優れていませんスレッドプール。
JAVAによる4スレッドプールエグゼキュータファクトリクラスを提供し、すなわち、:
- newCachedThreadPool:、長い治療の必要がある場合よりもリサイクル可能でない場合には、アイドル状態のスレッドを再利用するか、新しいスレッドを作成するための柔軟性をキャッシュスレッドプール、スレッドプールを作成します。(制御不能な同時スレッドの最大数)
- newFixedThreadPoolは:固定サイズのスレッドプールを作成し、あなたが同時スレッドの最大数を制御することができ、余分なスレッドは、キュー内で待機します。
- newScheduledThreadPool:定期的かつ定期的なタスクの実行をサポートするために、タイマースレッド・プールを作成します。
- newSingleThreadExecutor:すべてのタスクが指定された順(FIFO、LIFO、優先順位)で実行されることを保証するタスクのみワーカースレッドを実行するためにのみ使用し、シングルスレッドのスレッドプールを作成します。
スレッドプールの4種類のは、統一されたスレッドのタスクを作成してみましょう、便利なテスト
public class MyRunnable implements Runnable {
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + " is running...");
}
}
newSingleThreadExecutor
public class SingleThreadExecutorTest {
public static void main(String[] args) {
ExecutorService executorService = Executors.newSingleThreadExecutor();
MyRunnable myRunnable = new MyRunnable();
for (int i = 0; i < 5; i++) {
executorService.execute(myRunnable);
}
System.out.println("线程任务开始执行");
executorService.shutdown();
}
}
出力
线程任务开始执行
pool-1-thread-1 is running...
pool-1-thread-1 is running...
pool-1-thread-1 is running...
pool-1-thread-1 is running...
pool-1-thread-1 is running...
基本となる実装
/**
* 核心线程池大小=1
* 最大线程池大小为1
* 线程过期时间为0ms
* LinkedBlockingQueue作为工作队列
*/
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
以下のようなパラメータ、SingleThreadExecutor同等の特別FixedThreadPoolから見ることができ、その実行プロセスは、次のとおりです。
- 何のスレッドプールのスレッドが存在しない場合は、新しいスレッドがタスクを実行するには
- 将来的には、スレッド、ブロックされたキューにタスクに加え、ノンストップがあります
- これは、タスクの実行キューをとり続けるための唯一のスレッドであります
タスクのシリアル実行のためのSingleThreadExecutorシナリオは、各タスクは、順序で実行する必要があります同時に実行する必要はありません。
newFixedThreadPool
public class FixedThreadPoolTest {
public static void main(String[] args) {
ExecutorService executorService = Executors.newFixedThreadPool(2);
MyRunnable myRunnable = new MyRunnable();
for (int i = 0; i < 5; i++) {
executorService.execute(myRunnable);
}
System.out.println("线程任务开始执行");
executorService.shutdown();
}
}
出力
线程任务开始执行
pool-1-thread-1 is running...
pool-1-thread-1 is running...
pool-1-thread-2 is running...
pool-1-thread-1 is running...
pool-1-thread-2 is running...
基本となる実装
/**
* 核心线程池大小=传入参数
* 最大线程池大小为传入参数
* 线程过期时间为0ms
* LinkedBlockingQueue作为工作队列
*/
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
あなたは、スレッドプールのスレッド内のスレッドの数はコアの数を超えた場合つまり、タスクはブロッキングキューに配置され、スレッドのコア数と値を指定しているFixedThreadPoolスレッドの最大数を見ることができます。
またkeepAliveTimeがは、空きスレッドの過剰を直ちに終了されますつまり、(余分なスレッドが存在しないため、このパラメータはまた、何の意味ではありません)、0です。
そして、ここでブロッキングキューLinkedBlockingQueueの選択である、Integer.MAX_VALUEでのデフォルトの容量は、上限なしに対応し、使用されています。
そこで、次のようなタスク処理を実行するために、このスレッドプールは次のとおりです。
- スレッドの数はスレッドのコア数より少ないスレッドの数は、新しいスレッドがタスクを実行するとき
- スレッドの数に等しいスレッドのコア数の後、タスクキューにブロックされました
- キューの容量が非常に大きいため、いつでも追加することができます
- 繰り返しタスク実行キューに取られたタスクを実行するスレッド
資源の合理的利用へのサーバーのFixedThreadPool重い負荷、現在のスレッドの数を制限する必要があります。
newCachedThreadPool
public class CachedThreadPoolTest {
public static void main(String[] args) {
ExecutorService executorService = Executors.newCachedThreadPool();
MyRunnable myRunnable = new MyRunnable();
for (int i = 0; i < 5; i++) {
executorService.execute(myRunnable);
}
System.out.println("线程任务开始执行");
executorService.shutdown();
}
}
出力
线程任务开始执行
pool-1-thread-1 is running...
pool-1-thread-4 is running...
pool-1-thread-2 is running...
pool-1-thread-5 is running...
pool-1-thread-3 is running...
基本となる実装
/**
* 核心线程池大小=0
* 最大线程池大小为Integer.MAX_VALUE
* 线程过期时间为60s
* 使用SynchronousQueue作为工作队列
*/
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
あなたは何のコアスレッドは、非コアスレッドの数が上限、つまり、アウトソーシングのすべての使用ではありませんが、それぞれがわずか60秒のアイドル時間をアウトソーシング、そしてより後に回収され、CachedThreadPoolを見ることができます。
SynchronousQueueを使用してキューCachedThreadPoolは、この役割は、タスクキューを転送することで、保存されません。
そのため、速度は各タスクをコミットし、タスクに提出処理タスクの速度よりも大きい場合、それはスレッドを作成します。これは、CPUとメモリリソースの不足に極端な場合には、あまりにも多くのスレッドを作成します。
次のようにその実装方法は次のとおりです。
- いいえコアスレッドは、SynchronousQueueに直接ジョブを送信しません
- そこにアイドルスレッドがあり、タスクを実行するために出て行った場合、アイドル状態のスレッドが存在しない場合は、新しいものを作成
- タスクを実行するスレッドが別れそうでない場合、あなたはこの時間内に新しいタスクを受け取ることができるならば、私たちが生きるために続けることができ、生きるために60秒の時間を持っています
- 無料の60秒のスレッドが終了しますので、長時間のアイドルCachedThreadPoolがすべてのリソースを取らないまま。
小さな短期のタスク、または負荷の軽いサーバが多数の同時実行のためのCachedThreadPool。
newScheduledThreadPool
public class ScheduledThreadPoolTest {
public static void main(String[] args) {
ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(3);
MyRunnable myRunnable = new MyRunnable();
for (int i = 0; i < 5; i++) {
// 参数1:目标对象,参数2:隔多长时间开始执行线程,参数3:执行周期,参数4:时间单位
scheduledExecutorService.scheduleAtFixedRate(myRunnable, 1, 2, TimeUnit.SECONDS);
}
System.out.println("线程任务开始执行");
}
}
出力
线程任务开始执行
// 打印【线程任务开始执行】后1秒输出
pool-1-thread-1 is running...
pool-1-thread-2 is running...
pool-1-thread-1 is running...
pool-1-thread-3 is running...
pool-1-thread-2 is running...
// 2秒后输出
pool-1-thread-1 is running...
pool-1-thread-3 is running...
pool-1-thread-2 is running...
pool-1-thread-1 is running...
pool-1-thread-3 is running...
基本となる実装
/**
* 核心线程池大小=传入参数
* 最大线程池大小为Integer.MAX_VALUE
* 线程过期时间为0ms
* DelayedWorkQueue作为工作队列
*/
public ScheduledThreadPoolExecutor(int corePoolSize) {
super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
new DelayedWorkQueue());
}
次のようにScheduledThreadPoolExecutorの実装プロセスは、次のとおりです。
- タスクを追加します
- DelayQueueから仕事を取るために、プール内のスレッド
- その後、タスクを実行します
タスクを実行するための具体的な手順はより複雑です。
-
以上のスレッドがDelayQueueの現在時刻ScheduledFutureTaskから時刻を取得します
-
実行される次回のために時間を変更するには、このタスクの実行後
-
タスクは、キューに戻さ
ScheduledThreadPoolExecutorのは、より多くの背景定期的なタスクを実行するためのスレッド、およびスレッドのシーンの数を制限する必要性のために必要です。
エグゼキュータは、違いを作成し、ThreaPoolExecutorスレッドプール
各メソッドの執行の短所:
- newFixedThreadPoolとnewSingleThreadExecutorは:
主な問題は、要求処理キューの蓄積もOOM、非常に大容量のメモリを消費する可能性があります。 - newCachedThreadPoolとnewScheduledThreadPoolは:
主な問題は、スレッドの非常に多く、でもOOMを作成することができ、スレッドの最大数にInteger.MAX_VALUEです。
ThreaPoolExecutor
- スレッドプールを作成するための唯一の方法は、そのコンストラクタを取るに自分でパラメータを指定することです
タスクを実現するには、2つの方法
ExecutorServiceのタスクを提出する2つの方法を提供します。
- ()を実行:タスクが値を提出する必要はありません返します
- 提出():値を提出するために必要なタスクを返します。
実行
void execute(Runnable command);
パラメータは、()を実行Runnableをされ、戻り値はありません。そのため、提出後にタスクが正常に実行されたスレッド・プールであるかどうかを判断することはできません。
ExecutorService executor = Executors.newCachedThreadPool();
executor.execute(new Runnable() {
@Override
public void run() {
//do something
}
});
提出する
<T> Future<T> submit(Callable<T> task);
<T> Future<T> submit(Runnable task, T result);
Future<?> submit(Runnable task);
呼び出し可能なパラメータもRunnableを可能することができ、3ヘビーデューティーあります()を提出。
同時に、それは我々が成功したタスクを実行するかどうかを決定することができ、それを通してFuntureオブジェクトを返します。
タスクが完了するまで得られた結果は、現在のスレッドこの方法ブロック、Future.get()メソッドを呼び出します。
FutureTask一つのパッケージを使用する必要が呼び出し可能なタスクを提出するときは:
FutureTask futureTask = new FutureTask(new Callable<String>() { //创建 Callable 任务
@Override
public String call() throws Exception {
String result = "";
//do something
return result;
}
});
Future<?> submit = executor.submit(futureTask); //提交到线程池
try {
Object result = submit.get(); //获取结果
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}