みなさん、こんにちは。氷河です~~
Javaの同時実行性の高い分野では、スレッドプールは常に避けられないトピックでした。一部の子供靴はスレッドプールを使用していますが、スレッドプールを作成する方法は、Executorsツールクラスの使用の邪魔になるだけです。スレッドプールを作成する方法は何ですか?スレッドプールを作成するソースコードからスレッドプールを作成する方法を詳しく見てみましょう。
Executorsユーティリティクラスを使用してスレッドプールを作成します
スレッドプールを作成する場合、初心者はツールクラスExecutorsを最もよく使用し、このツールクラスを使用してスレッドプールを作成するのは非常に簡単です。スレッドプールの詳細にあまり注意を払う必要はなく、必要なのは必要なパラメータを渡すために。Executorsユーティリティクラスは、以下に示すように、スレッドプールを作成するためのいくつかのメソッドを提供します。
- Executors.newCachedThreadPool:キャッシュ可能なスレッドプールを作成します。スレッドプールのサイズが必要以上の場合、アイドル状態のスレッドを柔軟にリサイクルできます。リサイクル可能なスレッドがない場合は、新しいスレッドを作成します。
- Executors.newFixedThreadPool:固定長のスレッドプールを作成します。これにより、同時スレッドの最大数を制御でき、余分なスレッドはキューで待機します
- Executors.newScheduledThreadPool:スケジュールされた定期的なタスク実行をサポートするために、固定長のスレッドプールを作成します
- Executors.newSingleThreadExecutor:シングルスレッドスレッドプールを作成し、一意のワーカースレッドを使用してタスクを実行し、すべてのタスクが指定された順序(先入れ先出し、優先順位)で実行されるようにします。
- Executors.newSingleThreadScheduledExecutor:スケジュールされた定期的なタスク実行をサポートするシングルスレッドスレッドプールを作成します
- Executors.newWorkStealingPool:並列処理レベルでワークスティーリングスレッドプールを作成します
その中でも、Executors.newWorkStealingPoolメソッドは、Java 8でスレッドプールを作成するための新しいメソッドです。スレッドプールの並列処理レベルを設定でき、同時実行性とパフォーマンスが向上します。このメソッドに加えて、スレッドプールを作成する他のメソッドは、基本的にThreadPoolExecutorクラスのコンストラクターを呼び出します。
たとえば、次のコードを使用してスレッドプールを作成できます。
Executors.newWorkStealingPool();
Executors.newCachedThreadPool();
Executors.newScheduledThreadPool(3);
复制代码
ThreadPoolExecutorクラスを使用してスレッドプールを作成します
コード構造に関しては、ThreadPoolExecutorクラスはAbstractExecutorServiceを継承します。つまり、ThreadPoolExecutorクラスはAbstractExecutorServiceクラスのすべての機能を備えています。
Executorsツールクラスで作成されたスレッドプールのほとんどはThreadPoolExecutorクラスのコンストラクターを呼び出すため、Executorsツールクラスを使用する代わりに、ThreadPoolExecutorクラスのコンストラクターを直接呼び出してスレッドプールを作成することもできます。次に、ThreadPoolExecutorクラスのコンストラクターを見てみましょう。
ThreadPoolExecutorクラスのすべてのコンストラクターを以下に示します。
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), defaultHandler);
}
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
threadFactory, defaultHandler);
}
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
RejectedExecutionHandler handler) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), handler);
}
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) {
if (corePoolSize < 0 ||
maximumPoolSize <= 0 ||
maximumPoolSize < corePoolSize ||
keepAliveTime < 0)
throw new IllegalArgumentException();
if (workQueue == null || threadFactory == null || handler == null)
throw new NullPointerException();
this.acc = System.getSecurityManager() == null ?
null :
AccessController.getContext();
this.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.workQueue = workQueue;
this.keepAliveTime = unit.toNanos(keepAliveTime);
this.threadFactory = threadFactory;
this.handler = handler;
}
复制代码
ThreadPoolExecutorクラスのコンストラクターのソースコードからわかるように、スレッドプールを作成するために最終的に呼び出されるコンストラクターは次のとおりです。
public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize,
long keepAliveTime, TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) {
if (corePoolSize < 0 ||
maximumPoolSize <= 0 ||
maximumPoolSize < corePoolSize ||
keepAliveTime < 0)
throw new IllegalArgumentException();
if (workQueue == null || threadFactory == null || handler == null)
throw new NullPointerException();
this.acc = System.getSecurityManager() == null ?
null :
AccessController.getContext();
this.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.workQueue = workQueue;
this.keepAliveTime = unit.toNanos(keepAliveTime);
this.threadFactory = threadFactory;
this.handler = handler;
}
复制代码
この構築メソッドの各パラメーターの意味と機能については、「高並行性-私が言わなければならないスレッドプールとThreadPoolExecutorクラスの分析」を参照してください。
ThreadPoolExecutorクラスのコンストラクターを自分で呼び出すことにより、スレッドプールを作成できます。たとえば、次の形式を使用してスレッドプールを作成できます。
new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
复制代码
ForkJoinPoolクラスを使用してスレッドプールを作成します
Java8のExecutorsツールクラスには、スレッドプールを作成するための次のメソッドが追加されています。
public static ExecutorService newWorkStealingPool(int parallelism) {
return new ForkJoinPool
(parallelism,
ForkJoinPool.defaultForkJoinWorkerThreadFactory,
null, true);
}
public static ExecutorService newWorkStealingPool() {
return new ForkJoinPool
(Runtime.getRuntime().availableProcessors(),
ForkJoinPool.defaultForkJoinWorkerThreadFactory,
null, true);
}
复制代码
ソースコードから、はい、本質的に、ForkJoinPoolクラスのコンストラクタークラスが呼び出されてスレッドプールが作成され、コード構造の観点から、ForkJoinPoolクラスはAbstractExecutorService抽象クラスを継承します。次に、ForkJoinPoolクラスのコンストラクターを見てみましょう。
public ForkJoinPool() {
this(Math.min(MAX_CAP, Runtime.getRuntime().availableProcessors()),
defaultForkJoinWorkerThreadFactory, null, false);
}
public ForkJoinPool(int parallelism) {
this(parallelism, defaultForkJoinWorkerThreadFactory, null, false);
}
public ForkJoinPool(int parallelism,
ForkJoinWorkerThreadFactory factory,
UncaughtExceptionHandler handler,
boolean asyncMode) {
this(checkParallelism(parallelism),
checkFactory(factory),
handler,
asyncMode ? FIFO_QUEUE : LIFO_QUEUE,
"ForkJoinPool-" + nextPoolId() + "-worker-");
checkPermission();
}
private ForkJoinPool(int parallelism,
ForkJoinWorkerThreadFactory factory,
UncaughtExceptionHandler handler,
int mode,
String workerNamePrefix) {
this.workerNamePrefix = workerNamePrefix;
this.factory = factory;
this.ueh = handler;
this.config = (parallelism & SMASK) | mode;
long np = (long)(-parallelism); // offset ctl counts
this.ctl = ((np << AC_SHIFT) & AC_MASK) | ((np << TC_SHIFT) & TC_MASK);
}
复制代码
ソースコードを見ると、ForkJoinPoolのコンストラクターが最終的に次のプライベートコンストラクターを呼び出すことがわかります。
private ForkJoinPool(int parallelism,
ForkJoinWorkerThreadFactory factory,
UncaughtExceptionHandler handler,
int mode,
String workerNamePrefix) {
this.workerNamePrefix = workerNamePrefix;
this.factory = factory;
this.ueh = handler;
this.config = (parallelism & SMASK) | mode;
long np = (long)(-parallelism); // offset ctl counts
this.ctl = ((np << AC_SHIFT) & AC_MASK) | ((np << TC_SHIFT) & TC_MASK);
}
复制代码
各パラメータの意味は次のとおりです。
- 並列処理:並行性レベル。
- factory:スレッドを作成するファクトリクラスオブジェクト。
- handler:当线程池中的线程抛出未捕获的异常时,统一使用UncaughtExceptionHandler对象处理。
- mode:取值为FIFO_QUEUE或者LIFO_QUEUE。
- workerNamePrefix:执行任务的线程名称的前缀。
当然,私有构造方法虽然是参数最多的一个方法,但是其不会直接对外方法,我们可以使用如下方式创建线程池。
new ForkJoinPool();
new ForkJoinPool(Runtime.getRuntime().availableProcessors());
new ForkJoinPool(Runtime.getRuntime().availableProcessors(),
ForkJoinPool.defaultForkJoinWorkerThreadFactory,
null, true);
复制代码
使用ScheduledThreadPoolExecutor类创建线程池
在Executors工具类中存在如下方法类创建线程池。
public static ScheduledExecutorService newSingleThreadScheduledExecutor() {
return new DelegatedScheduledExecutorService
(new ScheduledThreadPoolExecutor(1));
}
public static ScheduledExecutorService newSingleThreadScheduledExecutor(ThreadFactory threadFactory) {
return new DelegatedScheduledExecutorService
(new ScheduledThreadPoolExecutor(1, threadFactory));
}
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
return new ScheduledThreadPoolExecutor(corePoolSize);
}
public static ScheduledExecutorService newScheduledThreadPool(
int corePoolSize, ThreadFactory threadFactory) {
return new ScheduledThreadPoolExecutor(corePoolSize, threadFactory);
}
复制代码
从源码来看,这几个方法本质上调用的都是ScheduledThreadPoolExecutor类的构造方法,ScheduledThreadPoolExecutor中存在的构造方法如下所示。
public ScheduledThreadPoolExecutor(int corePoolSize) {
super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
new DelayedWorkQueue());
}
public ScheduledThreadPoolExecutor(int corePoolSize, ThreadFactory threadFactory) {
super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
new DelayedWorkQueue(), threadFactory);
}
public ScheduledThreadPoolExecutor(int corePoolSize, RejectedExecutionHandler handler) {
super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
new DelayedWorkQueue(), handler);
}
public ScheduledThreadPoolExecutor(int corePoolSize,ThreadFactory threadFactory, RejectedExecutionHandler handler) {
super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
new DelayedWorkQueue(), threadFactory, handler);
}
复制代码
而从代码结构上看,ScheduledThreadPoolExecutor类继承自ThreadPoolExecutor类,本质上还是调用ThreadPoolExecutor类的构造方法,只不过此时传递的队列为DelayedWorkQueue。我们可以直接调用ScheduledThreadPoolExecutor类的构造方法来创建线程池,例如以如下形式创建线程池。
new ScheduledThreadPoolExecutor(3)
复制代码
好了,今天就到这儿吧,我是冰河,我们下期见~~