JDK1.5スレッドプール-ThreadPoolExecutorスレッドプールの作成
スレッドプールの概要は前の記事を参照してください.ここでは、ThreadPoolExecutorを使用してスレッドプールを作成する方法について説明します.
実行結果:
put i:0
Thread[pool-1-thread-1,5,main] index:0
put i:1
Thread[pool-1-thread-2,5,main] index:1
put i:2
put i:3
put i:4
put i:5
キューがいっぱいです.3秒待ってからタスクを追加します.
Thread[pool-1-thread-1,5,main] index:2
Thread[pool-1-thread-2,5,main] index:3
put i:6
put i:7
キューがいっぱいです.3秒待ってからタスクを追加します.
Thread[pool-1-thread-1,5,main] index:4
Thread[pool-1-thread-2,5,main] index:5
put i:8
put i:9
Thread[pool-1-thread-1,5,main] index:6
Thread[pool-1-thread-2,5,main] index:7
Thread[pool-1-thread-1,5,main] index:8
Thread[pool-1-thread-2,5,main] index:9
ここで使用する境界付きキューは、リソースの消費を防止するのに役立ち、キューサイズと最大プールサイズは互いにトレードオフする必要がある場合があります.大規模なキューと小型プールを使用すると、CPUの使用率、OSリソース、コンテキスト切替のオーバーヘッドを最大限に低減できますが、ワークフローのスループットを低下させる可能性があります.タスクが頻繁にブロックされている場合(たとえば、I/O境界の場合)、システムはライセンスを超えるスレッドに時間を割り当てる可能性があります.小型キューを使用するには、通常、プールサイズが大きく、CPUの使用率が高い必要がありますが、許容できないスケジューリングオーバーヘッドが発生する可能性があります.これにより、スループットも低下します.
import java.util.Queue;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class ThreadPoolExecutorTest {
private static int queueDeep = 4;
public void createThreadPool() {
/*
* , 2, 4, 3 ,
* 4 , , ,
* ( , ), 。
*/
ThreadPoolExecutor tpe = new ThreadPoolExecutor(2, 4, 3,
TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(queueDeep),
new ThreadPoolExecutor.DiscardOldestPolicy());
// 10
for (int i = 0; i < 10; i++) {
try {
Thread.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
while (getQueueSize(tpe.getQueue()) >= queueDeep) {
System.out.println(" , 3 ");
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
TaskThreadPool ttp = new TaskThreadPool(i);
System.out.println("put i:" + i);
tpe.execute(ttp);
}
tpe.shutdown();
}
private synchronized int getQueueSize(Queue queue) {
return queue.size();
}
public static void main(String[] args) {
ThreadPoolExecutorTest test = new ThreadPoolExecutorTest();
test.createThreadPool();
}
class TaskThreadPool implements Runnable {
private int index;
public TaskThreadPool(int index) {
this.index = index;
}
public void run() {
System.out.println(Thread.currentThread() + " index:" + index);
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
実行結果:
put i:0
Thread[pool-1-thread-1,5,main] index:0
put i:1
Thread[pool-1-thread-2,5,main] index:1
put i:2
put i:3
put i:4
put i:5
キューがいっぱいです.3秒待ってからタスクを追加します.
Thread[pool-1-thread-1,5,main] index:2
Thread[pool-1-thread-2,5,main] index:3
put i:6
put i:7
キューがいっぱいです.3秒待ってからタスクを追加します.
Thread[pool-1-thread-1,5,main] index:4
Thread[pool-1-thread-2,5,main] index:5
put i:8
put i:9
Thread[pool-1-thread-1,5,main] index:6
Thread[pool-1-thread-2,5,main] index:7
Thread[pool-1-thread-1,5,main] index:8
Thread[pool-1-thread-2,5,main] index:9
ここで使用する境界付きキューは、リソースの消費を防止するのに役立ち、キューサイズと最大プールサイズは互いにトレードオフする必要がある場合があります.大規模なキューと小型プールを使用すると、CPUの使用率、OSリソース、コンテキスト切替のオーバーヘッドを最大限に低減できますが、ワークフローのスループットを低下させる可能性があります.タスクが頻繁にブロックされている場合(たとえば、I/O境界の場合)、システムはライセンスを超えるスレッドに時間を割り当てる可能性があります.小型キューを使用するには、通常、プールサイズが大きく、CPUの使用率が高い必要がありますが、許容できないスケジューリングオーバーヘッドが発生する可能性があります.これにより、スループットも低下します.