ThreadPoolExecutorの観点から話をすると、コアプールサイズと最大プールサイズの違いは何ですか?例の助けを借りて説明できますか?
このブログ投稿 から:
この例を見てください。開始スレッドプールサイズは1、コアプールサイズは5、最大プールサイズは10、キューは100です。
要求が来ると、スレッドは最大5つ作成され、タスクは100に達するまでキューに追加されます。キューがいっぱいになると、新しいスレッドが
maxPoolSize
まで作成されます。すべてのスレッドが使用され、キューがいっぱいになると、タスクは拒否されます。キューが減少すると、アクティブなスレッドの数も減少します。
IF 実行中のスレッド> corePoolSize&<maxPoolSize、合計タスクキューがいっぱいで新しいキューが到着している場合、新しいスレッドを作成します。
フォームドキュメント:(corePoolSize以上でmaximumPoolSize未満のスレッドが実行されている場合、キューがいっぱいの場合にのみ新しいスレッドが作成されます。)
では、簡単な例を見てみましょう。
ThreadPoolExecutor executorPool = new ThreadPoolExecutor(5, 10, 3, TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(50));
ここで、5はcorePoolSizeです-Jvmは、最初の5つのタスクに対して新しいタスクの新しいスレッドを作成することを意味します。キューがいっぱいになるまで他のタスクがキューに追加されます(50タスク)。
10はmaxPoolSize-JVMは最大10個のスレッドを作成できます。すでに5つのタスク/スレッドが実行されており、キューが50の保留中のタスクでいっぱいであり、さらに1つの新しいリクエスト/タスクがキューに到着している場合、JVMは最大10の新しいスレッドを作成します(合計スレッド=前の5+新しい5) ;
new ArrayBlockingQueue(50) =は合計キューサイズです-50個のタスクをキューに入れることができます。
10個すべてのスレッドが実行され、新しいタスクが到着すると、その新しいタスクは拒否されます。
Sunが内部でスレッドを作成するためのルール:
スレッドの数がcorePoolSizeより小さい場合は、新しいスレッドを作成して新しいタスクを実行します。
スレッドの数がcorePoolSizeと等しい(または大きい)場合、タスクをキューに入れます。
キューがいっぱいで、スレッドの数がmaxPoolSizeより小さい場合、タスクを実行する新しいスレッドを作成します。
キューがいっぱいで、スレッドの数がmaxPoolSize以上の場合、タスクを拒否します。
希望、これはHelpFulです..間違っている場合は私を修正してください...
ドキュメント から:
メソッドexecute(Java.lang.Runnable)で新しいタスクが送信され、corePoolSizeスレッドよりも少ないスレッドが実行されると、他のワーカースレッドがアイドル状態であっても、リクエストを処理するための新しいスレッドが作成されます。 corePoolSizeより多く、maximumPoolSize未満のスレッドが実行されている場合、キューがいっぱいの場合にのみ新しいスレッドが作成されます。
さらに:
CorePoolSizeとmaximumPoolSizeを同じに設定することにより、固定サイズのスレッドプールを作成します。 maximumPoolSizeをInteger.MAX_VALUEなどの本質的に無制限の値に設定することにより、プールが任意の数の同時タスクに対応できるようにします。最も一般的には、コアおよび最大プールサイズは構築時にのみ設定されますが、setCorePoolSize(int)およびsetMaximumPoolSize(int)を使用して動的に変更することもできます。
ThreadPoolExecutor
ファクトリクラスを使用する代わりにExecutors
を手動で作成する場合は、コンストラクターの1つを使用して作成および構成する必要があります。このクラスの最も広範なコンストラクタは次のとおりです。
public ThreadPoolExecutor(
int corePoolSize,
int maxPoolSize,
long keepAlive,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
RejectedExecutionHandler handler
);
ご覧のとおり、以下を構成できます。
実行中の同時タスクの数を制限し、スレッドプールのサイズを変更することは、予測可能性と安定性の点で、アプリケーションとその実行環境に大きな利点をもたらします。 、アプリケーションの不安定性につながる可能性がある深刻なパフォーマンスの問題。
これは、問題の一部の解決策です。実行中のタスクの数を制限しているが、後で実行するために送信およびキューに入れることができるジョブの数を制限していません。アプリケーションは後でリソース不足を経験しますが、提出率が一貫して実行率を上回る場合、最終的にはリソース不足を経験します。
この問題の解決策は次のとおりです。待機キューをエグゼキューターに提供して、待機中のタスクを保持します。キューがいっぱいになると、送信されたタスクは「拒否」されます。 RejectedExecutionHandler
は、タスクの送信が拒否されたときに呼び出されます。そのため、拒否された動詞は前の項目で引用されました。独自の拒否ポリシーを実装するか、フレームワークが提供する組み込みポリシーのいずれかを使用できます。
デフォルトの拒否ポリシーでは、executorがRejectedExecutionException
をスローします。ただし、他の組み込みポリシーでは次のことができます。
Javadocでcorepoolsizeおよびmaxpoolsizeという用語の定義を見つけることができます。 http://docs.Oracle.com/javase/6/docs/api/Java/util/concurrent/ThreadPoolExecutor.html
上記のリンクには質問への回答があります。ただし、明確にするためです。アプリケーションは、corePoolSizeに達するまでスレッドを作成し続けます。ここでの考え方は、これらの多くのスレッドでタスクの流入を処理するのに十分であるべきだと思います。 corePoolSizeスレッドが作成された後に新しいタスクが来ると、タスクはキューに入れられます。キューがいっぱいになると、executorは新しいスレッドの作成を開始します。それは一種のバランスです。それが本質的に意味することは、タスクの流入が処理能力以上であることです。そのため、Executorは、スレッドの最大数に達するまで新しいスレッドの作成を再開します。繰り返しますが、キューがいっぱいの場合にのみ、新しいスレッドが作成されます。
this ブログの説明:
public class ThreadPoolExecutorExample {
public static void main (String[] args) {
createAndRunPoolForQueue(new ArrayBlockingQueue<Runnable>(3), "Bounded");
createAndRunPoolForQueue(new LinkedBlockingDeque<>(), "Unbounded");
createAndRunPoolForQueue(new SynchronousQueue<Runnable>(), "Direct hand-off");
}
private static void createAndRunPoolForQueue (BlockingQueue<Runnable> queue,
String msg) {
System.out.println("---- " + msg + " queue instance = " +
queue.getClass()+ " -------------");
ThreadPoolExecutor e = new ThreadPoolExecutor(2, 5, Long.MAX_VALUE,
TimeUnit.NANOSECONDS, queue);
for (int i = 0; i < 10; i++) {
try {
e.execute(new Task());
} catch (RejectedExecutionException ex) {
System.out.println("Task rejected = " + (i + 1));
}
printStatus(i + 1, e);
}
e.shutdownNow();
System.out.println("--------------------\n");
}
private static void printStatus (int taskSubmitted, ThreadPoolExecutor e) {
StringBuilder s = new StringBuilder();
s.append("poolSize = ")
.append(e.getPoolSize())
.append(", corePoolSize = ")
.append(e.getCorePoolSize())
.append(", queueSize = ")
.append(e.getQueue()
.size())
.append(", queueRemainingCapacity = ")
.append(e.getQueue()
.remainingCapacity())
.append(", maximumPoolSize = ")
.append(e.getMaximumPoolSize())
.append(", totalTasksSubmitted = ")
.append(taskSubmitted);
System.out.println(s.toString());
}
private static class Task implements Runnable {
@Override
public void run () {
while (true) {
try {
Thread.sleep(1000000);
} catch (InterruptedException e) {
break;
}
}
}
}
}
出力:
---- Bounded queue instance = class Java.util.concurrent.ArrayBlockingQueue -------------
poolSize = 1, corePoolSize = 2, queueSize = 0, queueRemainingCapacity = 3, maximumPoolSize = 5, totalTasksSubmitted = 1
poolSize = 2, corePoolSize = 2, queueSize = 0, queueRemainingCapacity = 3, maximumPoolSize = 5, totalTasksSubmitted = 2
poolSize = 2, corePoolSize = 2, queueSize = 1, queueRemainingCapacity = 2, maximumPoolSize = 5, totalTasksSubmitted = 3
poolSize = 2, corePoolSize = 2, queueSize = 2, queueCapacity = 1, maximumPoolSize = 5, totalTasksSubmitted = 4
poolSize = 2, corePoolSize = 2, queueSize = 3, queueRemainingCapacity = 0, maximumPoolSize = 5, totalTasksSubmitted = 5
poolSize = 3, corePoolSize = 2, queueSize = 3, queueRemainingCapacity = 0, maximumPoolSize = 5, totalTasksSubmitted = 6
poolSize = 4, corePoolSize = 2, queueSize = 3, queueRemainingCapacity = 0, maximumPoolSize = 5, totalTasksSubmitted = 7
poolSize = 5, corePoolSize = 2, queueSize = 3, queueRemainingCapacity = 0, maximumPoolSize = 5, totalTasksSubmitted = 8
Task rejected = 9
poolSize = 5, corePoolSize = 2, queueSize = 3, queueRemainingCapacity = 0, maximumPoolSize = 5, totalTasksSubmitted = 9
Task rejected = 10
poolSize = 5, corePoolSize = 2, queueSize = 3, queueRemainingCapacity = 0, maximumPoolSize = 5, totalTasksSubmitted = 10
--------------------
---- Unbounded queue instance = class Java.util.concurrent.LinkedBlockingDeque -------------
poolSize = 1, corePoolSize = 2, queueSize = 0, queueRemainingCapacity = 2147483647, maximumPoolSize = 5, totalTasksSubmitted = 1
poolSize = 2, corePoolSize = 2, queueSize = 0, queueRemainingCapacity = 2147483647, maximumPoolSize = 5, totalTasksSubmitted = 2
poolSize = 2, corePoolSize = 2, queueSize = 1, queueRemainingCapacity = 2147483646, maximumPoolSize = 5, totalTasksSubmitted = 3
poolSize = 2, corePoolSize = 2, queueSize = 2, queueRemainingCapacity = 2147483645, maximumPoolSize = 5, totalTasksSubmitted = 4
poolSize = 2, corePoolSize = 2, queueSize = 3, queueRemainingCapacity = 2147483644, maximumPoolSize = 5, totalTasksSubmitted = 5
poolSize = 2, corePoolSize = 2, queueSize = 4, queueRemainingCapacity = 2147483643, maximumPoolSize = 5, totalTasksSubmitted = 6
poolSize = 2, corePoolSize = 2, queueSize = 5, queueRemainingCapacity = 2147483642, maximumPoolSize = 5, totalTasksSubmitted = 7
poolSize = 2, corePoolSize = 2, queueSize = 6, queueRemainingCapacity = 2147483641, maximumPoolSize = 5, totalTasksSubmitted = 8
poolSize = 2, corePoolSize = 2, queueSize = 7, queueRemainingCapacity = 2147483640, maximumPoolSize = 5, totalTasksSubmitted = 9
poolSize = 2, corePoolSize = 2, queueSize = 8, queueRemainingCapacity = 2147483639, maximumPoolSize = 5, totalTasksSubmitted = 10
--------------------
---- Direct hand-off queue instance = class Java.util.concurrent.SynchronousQueue -------------
poolSize = 1, corePoolSize = 2, queueSize = 0, queueRemainingCapacity = 0, maximumPoolSize = 5, totalTasksSubmitted = 1
poolSize = 2, corePoolSize = 2, queueSize = 0, queueRemainingCapacity = 0, maximumPoolSize = 5, totalTasksSubmitted = 2
poolSize = 3, corePoolSize = 2, queueSize = 0, queueRemainingCapacity = 0, maximumPoolSize = 5, totalTasksSubmitted = 3
poolSize = 4, corePoolSize = 2, queueSize = 0, queueRemainingCapacity = 0, maximumPoolSize = 5, totalTasksSubmitted = 4
poolSize = 5, corePoolSize = 2, queueSize = 0, queueRemainingCapacity = 0, maximumPoolSize = 5, totalTasksSubmitted = 5
Task rejected = 6
poolSize = 5, corePoolSize = 2, queueSize = 0, queueRemainingCapacity = 0, maximumPoolSize = 5, totalTasksSubmitted = 6
Task rejected = 7
poolSize = 5, corePoolSize = 2, queueSize = 0, queueRemainingCapacity = 0, maximumPoolSize = 5, totalTasksSubmitted = 7
Task rejected = 8
poolSize = 5, corePoolSize = 2, queueSize = 0, queueRemainingCapacity = 0, maximumPoolSize = 5, totalTasksSubmitted = 8
Task rejected = 9
poolSize = 5, corePoolSize = 2, queueSize = 0, queueRemainingCapacity = 0, maximumPoolSize = 5, totalTasksSubmitted = 9
Task rejected = 10
poolSize = 5, corePoolSize = 2, queueSize = 0, queueRemainingCapacity = 0, maximumPoolSize = 5, totalTasksSubmitted = 10
--------------------
Process finished with exit code 0
Java.util.concurrent.ThreadPoolExecutor
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
/*
* Proceed in 3 steps:
*
* 1. If fewer than corePoolSize threads are running, try to
* start a new thread with the given command as its first
* task. The call to addWorker atomically checks runState and
* workerCount, and so prevents false alarms that would add
* threads when it shouldn't, by returning false.
*
* 2. If a task can be successfully queued, then we still need
* to double-check whether we should have added a thread
* (because existing ones died since last checking) or that
* the pool shut down since entry into this method. So we
* recheck state and if necessary roll back the enqueuing if
* stopped, or start a new thread if there are none.
*
* 3. If we cannot queue task, then we try to add a new
* thread. If it fails, we know we are shut down or saturated
* and so reject the task.
*/
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);
}
本からJavaの同時性の本質:
CorePoolSize:ThreadPoolExecutorには、キューがいっぱいになったときにのみ新しいスレッドが開始されるまで開始するスレッド数を決定する属性corePoolSizeがあります。
MaximumPoolSize:この属性は、最大で起動されるスレッドの数を決定します。これを整数に設定できます。上限を持たないためのMAX_VALUE