Javaでスレッドプールを作成するには、一般に2つの方法があります。
1. Executorsファクトリメソッド
によって作成されnew ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue)
ます。2. カスタムによって作成されます。
1つは、Executorsファクトリメソッドの作成
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class TestThreadPoolExecutor {
public static void main(String[] args) {
//创建使用单个线程的线程池
ExecutorService es1 = Executors.newSingleThreadExecutor();
for (int i = 0; i < 10; i++) {
es1.submit(() -> System.out.println(Thread.currentThread().getName() + "正在执行任务"));
}
//创建使用固定线程数的线程池
ExecutorService es2 = Executors.newFixedThreadPool(3);
for (int i = 0; i < 10; i++) {
es2.submit(() -> System.out.println(Thread.currentThread().getName() + "正在执行任务"));
}
//创建一个会根据需要创建新线程的线程池
ExecutorService es3 = Executors.newCachedThreadPool();
for (int i = 0; i < 20; i++) {
es3.submit(() -> System.out.println(Thread.currentThread().getName() + "正在执行任务"));
}
//创建拥有固定线程数量的定时线程任务的线程池
ScheduledExecutorService es4 = Executors.newScheduledThreadPool(2);
System.out.println("时间:" + System.currentTimeMillis());
for (int i = 0; i < 5; i++) {
es4.schedule(() -> System.out.println("时间:" + System.currentTimeMillis() + "--" + Thread.currentThread().getName() + "正在执行任务"), 3, TimeUnit.SECONDS);
}
//创建只有一个线程的定时线程任务的线程池
ScheduledExecutorService es5 = Executors.newSingleThreadScheduledExecutor();
System.out.println("时间:" + System.currentTimeMillis());
for (int i = 0; i < 5; i++) {
es5.schedule(() -> System.out.println("时间:" + System.currentTimeMillis() + "--" + Thread.currentThread().getName() + "正在执行任务"), 3, TimeUnit.SECONDS);
}
}
}
2、新しいThreadPoolExecutor()カスタム作成
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize,long keepAliveTime,TimeUnit unit,BlockingQueue workQueue,ThreadFactory threadFactory,RejectedExecutionHandler handler) ;
corePoolSize
:コアプールのサイズこのパラメーターは、後で説明するスレッドプールの実装原理と非常に大きな関係があります。スレッドプールが作成された後、デフォルトでは、スレッドプールにはスレッドはありません。代わりに、タスクを実行するスレッドを作成する前に、タスクが到着するのを待ちます。prestartAllCoreThreads()
またはprestartCoreThread()
メソッドが呼び出されない限り、これら2つのメソッドの名前から確認できます。これは、事前に作成されたスレッド、つまり、タスクが到着しない前に、corePoolSizeスレッドまたは1つのスレッドが作成されることを意味します。デフォルトでは、スレッドプールが作成された後、スレッドプール内のスレッド数は0です。タスクが来ると、タスクを実行するためのスレッドが作成されます。スレッドプール内のスレッド数がcorePoolSizeに達すると、スレッドはタスクをキャッシュキューに入れます。:
maximumPoolSize
スレッドプール内のスレッドの最大数。このパラメーターも非常に重要なパラメーターです。これは、スレッドプールで作成できるスレッドの最大数を
keepAliveTime
示します。:タスクが実行されていないときにスレッドが終了する時間を示します。 。デフォルトではcorePoolSize
、それはkeepAliveTime
のみ動作しますとき、スレッドプール内のスレッドの数がより大きいこと、スレッドプール内のスレッドの数がより大きくないまでcorePoolSize
つまり、スレッドプール内のスレッドの数がより大きい場合corePoolSize
であれば、スレッドが到達するのアイドル時間、keepAliveTime
、その後、スレッドプール内のスレッド数がを超えなくなるまで終了しますcorePoolSize
。ただし、allowCoreThreadTimeOut(boolean)
メソッドが呼び出された場合、スレッドプール内のスレッド数がを超えない場合corePoolSize
、keepAliveTime
スレッドプール内のスレッド数が0になるまでパラメーターも機能し
unit
ます;:パラメーターのkeepAliveTime
時間単位、7つの値、TimeUnit
クラスには7つあります静的プロパティの種類:
TimeUnit.DAYS; //天
TimeUnit.HOURS; //小时
TimeUnit.MINUTES; //分钟
TimeUnit.SECONDS; //秒
TimeUnit.MILLISECONDS; //毫秒
TimeUnit.MICROSECONDS; //微妙
TimeUnit.NANOSECONDS; //纳秒
workQueue
:ブロッキングキューは、実行を待機しているタスクを格納するために使用されます。このパラメーターの選択も非常に重要であり、スレッドプールの実行中のプロセスに大きな影響を与えます。一般的に、ブロッキングキューにはいくつかのオプションがあります。
ArrayBlockingQueue
LinkedBlockingQueue
SynchronousQueue
PriorityBlockingQueue
ArrayBlockingQueue
そしてPriorityBlockingQueue
使用し、一般的に、あまり使用LinkedBlockingQueue
してSynchronousQueue
。スレッドプールのキューイング戦略はBlockingQueue
関連しています。
threadFactory
:スレッドを作成するためのファクトリを設定するために使用されます。デーモンや優先度の設定など、スレッドファクトリを介して、作成された各スレッドに対してより意味のあることを実行できます
handler
。:タスクが拒否された場合の戦略を示します。次の4つがあります。値:
1、AbortPolicy:直接抛出异常。
2、CallerRunsPolicy:只用调用者所在线程来运行任务。
3、DiscardOldestPolicy:丢弃队列里最近的一个任务,并执行当前任务。
4、DiscardPolicy:不处理,丢弃掉。
5、也可以根据应用场景需要来实现RejectedExecutionHandler接口自定义策略。如记录日志或持久化不能处理的任务。
import java.io.IOException;
import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;
public class ThreadTest {
public static void main(String[] args) throws IOException {
int corePoolSize = 2;
int maximumPoolSize = 4;
long keepAliveTime = 10;
TimeUnit unit = TimeUnit.SECONDS;
BlockingQueue<Runnable> workQueue = new ArrayBlockingQueue<>(2);
ThreadFactory threadFactory = new NameTreadFactory();
RejectedExecutionHandler handler = new MyIgnorePolicy();
ThreadPoolExecutor executor = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, unit,
workQueue, threadFactory, handler);
executor.prestartAllCoreThreads(); // 预启动所有核心线程
for (int i = 1; i <= 10; i++) {
MyTask task = new MyTask(String.valueOf(i));
executor.execute(task);
}
System.in.read(); //阻塞主线程
}
static class NameTreadFactory implements ThreadFactory {
private final AtomicInteger mThreadNum = new AtomicInteger(1);
@Override
public Thread newThread(Runnable r) {
Thread t = new Thread(r, "my-thread-" + mThreadNum.getAndIncrement());
System.out.println(t.getName() + " has been created");
return t;
}
}
public static class MyIgnorePolicy implements RejectedExecutionHandler {
public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
doLog(r, e);
}
private void doLog(Runnable r, ThreadPoolExecutor e) {
// 可做日志记录等
System.err.println(r.toString() + " rejected");
// System.out.println("completedTaskCount: " + e.getCompletedTaskCount());
}
}
static class MyTask implements Runnable {
private String name;
public MyTask(String name) {
this.name = name;
}
@Override
public void run() {
try {
System.out.println(this.toString() + " is running!");
Thread.sleep(3000); //让任务执行慢点
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public String getName() {
return name;
}
@Override
public String toString() {
return "MyTask [name=" + name + "]";
}
}
}
このうち、スレッドスレッド1〜4は最初にコアスレッドとスレッドの最大数を満たし、次にスレッド4および5が待機キューに入り、スレッド7〜10は直接無視されて実行が拒否され、スレッド4〜5はスレッド1〜4の実行後に通知されます。スレッドは実行を継続します。