线程池原理

所谓线程池,通俗的理解就是有一个池子,里面存放着已经创建好的线程,当有任务提 交给线程池执行时,池子中的某个线程会主动执行该任务。如果池子中的线程数量不够应付 数量众多的任务时,则需要自动扩充新的线程到池子中,但是该数量是有限的,就好比池塘 的水界线一样。当任务比较少的时候,池子中的线程能够自动回收,释放资源。为了能够异 步地提交任务和缓存未被处理的任务,需要有一个任务队列,如图所示。
自定义线程池及原理_线程池
通过上面的描述可知,一个完整的线程池应该具备如下要素。

  1. 任务队列:用于缓存提交的任务。
  2. 线程数量管理功能:一个线程池必须能够很好地管理和控制线程数量,可通过如下三个 参数来实现,比如创建线程池时初始的线程数量 init;线程池自动扩充时最大的线程 数量 max;在线程池空闲时需要释放线程但是也要维护一定数量的活跃数量或者核心数 量 core。有了这三个参数,就能够很好地控制线程池中的线程数量,将其维护在一个 合理的范围之内,三者之间的关系是 init<=core<=max。
  3. 任务拒绝策略:如果线程数量已达到上限且任务队列已满,则需要有相应的拒绝策略来 通知任务提交者。
  4. 线程工厂:主要用于个性化定制线程,比如将线程设置为守护线程以及设置线程名称等。
  5. QueueSize:任务队列主要存放提交的 Runnable,但是为了防止内存溢出,需要有 limit 数量对其进行控制。
  6. Keepedalive 时间:该时间主要决定线程各个重要参数自动维护的时间间隔。

线程池实现

下面我们实现一个比较简单的 ThreadPool,虽然比较简单,但是该有的功能基本上都 具备,对大家学习和掌握 JUC 中的 ExecutorService 也有一定的帮助。如图所示为线程 池实现类图。
自定义线程池及原理_线程池_02

  1. ThreadPool
    ThreadPool 主要定义了一个线程池应该具备的基本操作和方法,下面是 ThreadPool 接口定义的方法:
package com.neu.day06;

/**
* 线程池接口
*/
public interface ThreadPool {

// 提交任务到线程池
void execute(Runnable runnable);

// 关闭线程池
void shutdown();

// 查看线程池是否已经被 shutdown
boolean isShutdown();

// 获取线程池的初始化大小
int getInitSize();

// 获取线程池最大的线程数
int getMaxSize();

// 获取线程池的核心线程数量
int getCoreSize();

// 获取线程池用于缓存任务队列的大小
int getQueueSize();

// 获取线程池中活跃线程的数量
int getActiveCount();

}
  1. RunanbleQueue
    RunanbleQueue 主 要 用 于 存 放 提 交 的 Runnable , 该 Runnable 是 一 个 BlockedQueue,并且有 limit 的限制,示例代码如下。
package com.neu.day06;

/**
* 任务队列,主要用于缓存提交到线程池中的任务
*/
public interface RunnableQueue {

// 当有新的任务进来时首先会 offer 到队列中
void offer(Runnable runnable);

// 工作线程通过 take 方法获取 Runnable
Runnable take();

// 获取任务队列中任务的数量
int size();

}
  1. ThreadFactory
    ThreadFactory 提供了创建线程的接口,以便于个性化地定制 Thread,比如 Thread 应该被加到哪个 Group 中,优先级、线程名字以及是否为守护线程等,示例代码如下。
package com.neu.day06;

/**
* 创建线程的工厂
*/
@FunctionalInterface
public interface ThreadFactory {

Thread createThread(Runnable runnable);

}
  1. DenyPolicy
    DenyPolicy 主要用于当 Queue 中的 Runnable 达到了 limit 上限时,决定采用何种 策略通知提交者。该接口中定义了三种默认的实现,示例代码如下。
package com.neu.day06;

/**
* 拒绝策略
*/
@FunctionalInterface
public interface DenyPolicy {

void reject(Runnable runnable, ThreadPool threadPool);

// 该拒绝策略会直接将任务丢弃
class DiscardDenyPolicy implements DenyPolicy {
@Override
public void reject(Runnable runnable, ThreadPool threadPool) {
// ...
System.out.println(runnable + " 任务已被丢弃。");
}
}

// 该拒绝策略会向任务提交者抛出异常
class AbortDenyPolicy implements DenyPolicy {
@Override
public void reject(Runnable runnable, ThreadPool threadPool) {
throw new RunnableDenyException("任务 " + runnable + " 将被终止。");
}
}

// 该拒绝策略会使任务在提交者所在的线程中执行任务
class RunnerDenyPolicy implements DenyPolicy {
@Override
public void reject(Runnable runnable, ThreadPool threadPool) {
if (!threadPool.isShutdown())
runnable.run();
}
}

}
  1. RunnableDenyException
    RunnableDenyException 是 RuntimeException 的子类,主要用于通知任务提交者,任务队列已无法再接收新的任务。示例代码如下。
package com.neu.day06;

/**
* 自定义拒绝策略异常类
*/
public class RunnableDenyException extends RuntimeException {

public RunnableDenyException(String message) {
super(message);
}

}
  1. InternalTask
    InternalTask 是 Runnable 的一个实现,主要用于线程池内部,该类会使用到 RunnableQueue,然后不断地从 queue 中取出某个 Runnable,并运行 Runnable 的 run 方法,除此之外,代码还对该类增加了一个开关方法 stop,主要用于停止当前线程,一般 在线程池销毁和线程数量维护的时候会使用到。示例代码如下。
package com.neu.day06;

/**
* 任务类
*/
public class InternalTask implements Runnable {

private final RunnableQueue runnableQueue;
private volatile boolean running = true;

public InternalTask(RunnableQueue runnableQueue) {
this.runnableQueue = runnableQueue;
}

@Override
public void run() {
Runnable task = null;
// 如果当前任务为 running 并且没有被中断,则不断的从 queue 中获取 runnable 然后执行 run 方法
while (running && !Thread.currentThread().isInterrupted()) {
task = runnableQueue.take();
task.run();
}
}

// 停止当前任务,主要会在线程池的 shutdown 方法中使用
public void stop() {
this.running = false;
}

}

线程池详细实现

  1. LinkedRunnableQueue
package com.neu.day06;

import java.util.LinkedList;

public class LinkedRunnableQueue implements RunnableQueue {

// 任务队列的最大容量
private final int limit;
// 若任务队列中的任务已经满了,则需要执行拒绝策略
private final DenyPolicy denyPolicy;
// 存放任务的队列
private final LinkedList<Runnable> runnableList = new LinkedList<>();
private final ThreadPool threadPool;

public LinkedRunnableQueue(int limit, DenyPolicy denyPolicy, ThreadPool threadPool) {
this.limit = limit;
this.denyPolicy = denyPolicy;
this.threadPool = threadPool;
}

@Override
public void offer(Runnable runnable) {
synchronized (runnableList) {
if (runnableList.size() >= limit) {
// 无法容纳新的任务时执行拒绝策略
denyPolicy.reject(runnable, threadPool);
} else {
// 将任务加入到队尾,并且唤醒阻塞中的线程
runnableList.addLast(runnable);
runnableList.notifyAll();
}
}
}

@Override
public Runnable take() {
synchronized (runnableList) {
while (runnableList.isEmpty()) {
try {
// 如果任务队列中没有可执行的任务,则当前线程将会挂起
runnableList.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 从任务队列头部移除一个任务
return runnableList.removeFirst();
}
}

@Override
public int size() {
synchronized (runnableList) {
// 返回当前任务队列中的任务数
return runnableList.size();
}
}

}

在 LinkedRunnableQueue 中有几个重要的属性,第一个是 limit,也就是 Runnable 队列的上限;当提交的 Runnable 数量达到 limit 上限时,则会调用 DenyPolicy 的 reject 方法;RunnableList 是一个双向循环列表,用于存放 Runnable 任务,示例代码 如下:

@Override
public void offer(Runnable runnable) {
synchronized (runnableList) {
if (runnableList.size() >= limit) {
// 无法容纳新的任务时执行拒绝策略
denyPolicy.reject(runnable, threadPool);
} else {
// 将任务加入到队尾,并且唤醒阻塞中的线程
runnableList.addLast(runnable);
runnableList.notifyAll();
}
}
}

offer 方法是一个同步方法,如果队列数量达到了上限,则会执行拒绝策略,否则会将 Runnable 存放至队列中,同时唤醒 take 任务的线程:

@Override
public Runnable take() {
synchronized (runnableList) {
while (runnableList.isEmpty()) {
try {
// 如果任务队列中没有可执行的任务,则当前线程将会挂起
runnableList.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 从任务队列头部移除一个任务
return runnableList.removeFirst();
}
}

take 方法也是同步方法,线程不断从队列中获取 Runnable 任务,当队列为空的时候 工作线程会陷入阻塞,有可能在阻塞的过程中被中断,为了传递中断信号需要在 catch 语 句块中将异常抛出以通知上游(InternalTask)。 size 方法用于返回 runnablelist 的任务个数。

@Override
public int size() {
synchronized (runnableList) {
// 返回当前任务队列中的任务数
return runnableList.size();
}
}
  1. 初始化线程池BasicThreadPool
    根据前面的讲解,线程池需要有数量控制属性、创建线程工厂、任务队列策略等功能, 线程池初始化代码如下所示。
package com.neu.day06;

import java.util.ArrayDeque;
import java.util.Queue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;

public class BasicThreadPool extends Thread implements ThreadPool {

// 初始化线程数量
private final int initSize;
// 线程池最大线程数量
private final int maxSize;
// 线程池核心线程数量
private final int coreSize;
// 当前活跃的线程数量
private int activeCount;
// 线程池是否被 shutdown 的标记
private volatile boolean isShutdown = false;
// 线程存活时间
private final long keepAliveTime;
// 时间单位
private final TimeUnit timeUnit;
// 创建线程所需的工厂
private final ThreadFactory threadFactory;
private final static ThreadFactory DEFAULT_THREAD_FACTORY = new DefaultThreadFactory();

// 工厂实现类(内部类)
private static class DefaultThreadFactory implements ThreadFactory {
private static final AtomicInteger GROUP_COUNTER = new AtomicInteger(0);
private static final ThreadGroup GROUP = new ThreadGroup("MyThreadGroupPool-"
+ GROUP_COUNTER.getAndIncrement());
private static final AtomicInteger COUNTER = new AtomicInteger(0);

@Override
public Thread createThread(Runnable runnable) {
return new Thread(GROUP, runnable, "thread-pool-" + COUNTER.getAndIncrement());
}
}

// 任务队列
private final RunnableQueue runnableQueue;
// 工作线程队列
private final Queue<ThreadTask> threadQueue = new ArrayDeque();

private static class ThreadTask {
Thread thread;
InternalTask internalTask;

public ThreadTask(Thread thread, InternalTask internalTask) {
this.thread = thread;
this.internalTask = internalTask;
}
}

// 拒绝策略
private final static DenyPolicy DEFAULT_DENY_POLICY = new DenyPolicy.DiscardDenyPolicy();

// 构造器
public BasicThreadPool(int initSize, int maxSize, int coreSize, int queueSize) {
this(initSize, maxSize, coreSize, queueSize,
DEFAULT_DENY_POLICY, 10, TimeUnit.SECONDS,
DEFAULT_THREAD_FACTORY);
}

public BasicThreadPool(int initSize, int maxSize, int coreSize, int queueSize,
DenyPolicy denyPolicy, long keepAliveTime, TimeUnit timeUnit,
ThreadFactory threadFactory) {
this.initSize = initSize;
this.maxSize = maxSize;
this.coreSize = coreSize;
this.runnableQueue = new LinkedRunnableQueue(queueSize, denyPolicy, this);
this.keepAliveTime = keepAliveTime;
this.timeUnit = timeUnit;
this.threadFactory = threadFactory;
// 初始化线程池
init();
}

// 初始化线程池
private void init() {
this.start();
for (int i = 0; i < initSize; i++) {
newThread();
}
}

// 创建任务线程并启动
private void newThread() {
InternalTask internalTask = new InternalTask(runnableQueue);
Thread thread = this.threadFactory.createThread(internalTask);
ThreadTask threadTask = new ThreadTask(thread, internalTask);
threadQueue.offer(threadTask);
this.activeCount++;
thread.start();
}

// 从线程池中移除某个线程
private void removeThread() {
ThreadTask threadTask = threadQueue.remove();
threadTask.internalTask.stop();
this.activeCount--;
}

// 提交任务
@Override
public void execute(Runnable runnable) {
if (this.isShutdown)
throw new IllegalStateException("线程池已销毁。");
// 提交任务
this.runnableQueue.offer(runnable);
}

// 线程池自动维护
@Override
public void run() {
// 线程池没有被 shutdown 也没有中断的标记
while (!isShutdown && !isInterrupted()) {
try {
timeUnit.sleep(keepAliveTime);
} catch (InterruptedException e) {
e.printStackTrace();
}

synchronized (this) {
if (isShutdown)
break;
// 当前的队列中有任务尚未处理,并且 activeCount < coreSize 则继续扩容
if (runnableQueue.size() > 0 && activeCount < coreSize) {
for (int i = initSize; i < coreSize; i++) {
newThread();
}
continue;
}
// 当前的队列中有任务尚未处理,并且 activeCount < maxSize 则继续扩容
if (runnableQueue.size() > 0 && activeCount < maxSize) {
for (int i = coreSize; i < maxSize; i++) {
newThread();
}
}
// 当前的队列中没有任务,则需要回收,回收至 coreSize 即可
if (runnableQueue.size() == 0 && activeCount > coreSize) {
for (int i = coreSize; i < activeCount; i++) {
removeThread();
}
}
}
}
}

// 线程池销毁
@Override
public void shutdown() {
synchronized (this) {
if (isShutdown)
return;
isShutdown = true;
threadQueue.forEach(threadTask -> {
threadTask.internalTask.stop();
threadTask.thread.interrupt();
});
this.interrupt();
}
}

@Override
public boolean isShutdown() {
if (this.isShutdown)
throw new IllegalStateException("线程池已销毁。");
return this.isShutdown;
}

@Override
public int getInitSize() {
if (this.isShutdown)
throw new IllegalStateException("线程池已销毁。");
return this.initSize;
}

@Override
public int getMaxSize() {
if (this.isShutdown)
throw new IllegalStateException("线程池已销毁。");
return this.maxSize;
}

@Override
public int getCoreSize() {
if (this.isShutdown)
throw new IllegalStateException("线程池已销毁。");
return this.coreSize;
}

@Override
public int getQueueSize() {
if (this.isShutdown)
throw new IllegalStateException("线程池已销毁。");
return this.runnableQueue.size();
}

@Override
public int getActiveCount() {
if (this.isShutdown)
throw new IllegalStateException("线程池已销毁。");
return this.activeCount;
}

}
  1. 提交任务
    提交任务非常简单,只是将 Runnable 插人 runnableQueue 中即可。示例代码如下:
// 提交任务
@Override
public void execute(Runnable runnable) {
if (this.isShutdown)
throw new IllegalStateException("线程池已销毁。");
// 提交任务
this.runnableQueue.offer(runnable);
}
  1. 线程池自动维护
    线程池中线程数量的维护主要由 run 负责,这也是为什么 BasicThreadPool 继承自Thread 了,不过不推荐使用直接继承的方式,线程池自动维护代码如下:
// 创建任务线程并启动
private void newThread() {
InternalTask internalTask = new InternalTask(runnableQueue);
Thread thread = this.threadFactory.createThread(internalTask);
ThreadTask threadTask = new ThreadTask(thread, internalTask);
threadQueue.offer(threadTask);
this.activeCount++;
thread.start();
}

// 从线程池中移除某个线程
private void removeThread() {
ThreadTask threadTask = threadQueue.remove();
threadTask.internalTask.stop();
this.activeCount--;
}
// 线程池自动维护
@Override
public void run() {
// 线程池没有被 shutdown 也没有中断的标记
while (!isShutdown && !isInterrupted()) {
try {
timeUnit.sleep(keepAliveTime);
} catch (InterruptedException e) {
e.printStackTrace();
}

synchronized (this) {
if (isShutdown)
break;
// 当前的队列中有任务尚未处理,并且 activeCount < coreSize 则继续扩容
if (runnableQueue.size() > 0 && activeCount < coreSize) {
for (int i = initSize; i < coreSize; i++) {
newThread();
}
continue;
}
// 当前的队列中有任务尚未处理,并且 activeCount < maxSize 则继续扩容
if (runnableQueue.size() > 0 && activeCount < maxSize) {
for (int i = coreSize; i < maxSize; i++) {
newThread();
}
}
// 当前的队列中没有任务,则需要回收,回收至 coreSize 即可
if (runnableQueue.size() == 0 && activeCount > coreSize) {
for (int i = coreSize; i < activeCount; i++) {
removeThread();
}
}
}
}
}

下面重点来解说线程自动维护的方法,自动维护线程的代码块是同步代码块,主要是为 了阻止在线程维护过程中线程池销毁引起的数据不一致问题。 任 务 队 列 中 若 存 在 积 压 任 务 , 并 且 当 前 活 动 线 程 少 于 核 心 线 程 数 , 则 新 建 coreSize-initSize 数量的线程,并且将其加入到活动线程队列中,为了防止马上进行 maxSize-coreSize 数量的扩充,建议使用 continue 终止本次循环。 任务队列中有积压任务,并且当前活动线程少于最大线程数,则新建 max Size- core Size 数量的线程,并且将其加入到活动队列中。
当前线程池不够繁忙时,则需要回收部分线程,回收到 coreSize 数量即可,回收时 调用 removeThread 方法,在该方法中需要考虑的一点是,如果被回收的线程恰巧从 Runnable 任务取出了某个任务,则会继续保持该线程的运行,直到完成了任务的运行为止, 详见 InternalTask 的 run 方法。
5. 线程池销毁
线程池的销毁同样需要同步机制的保护,主要是为了防止与线程池本身的维护线程引起 数据冲突,线程池销毁代码如下:

// 线程池销毁
@Override
public void shutdown() {
synchronized (this) {
if (isShutdown)
return;
isShutdown = true;
threadQueue.forEach(threadTask -> {
threadTask.internalTask.stop();
threadTask.thread.interrupt();
});
this.interrupt();
}
}

销毁线程池主要为了是停止 BasicThreadPool 线程,停止线程池中的活动线程并且将 isShutdown 开关变量更改为 true。
6. 线程池的其他方法

@Override
public boolean isShutdown() {
if (this.isShutdown)
throw new IllegalStateException("线程池已销毁。");
return this.isShutdown;
}

@Override
public int getInitSize() {
if (this.isShutdown)
throw new IllegalStateException("线程池已销毁。");
return this.initSize;
}

@Override
public int getMaxSize() {
if (this.isShutdown)
throw new IllegalStateException("线程池已销毁。");
return this.maxSize;
}

@Override
public int getCoreSize() {
if (this.isShutdown)
throw new IllegalStateException("线程池已销毁。");
return this.coreSize;
}

@Override
public int getQueueSize() {
if (this.isShutdown)
throw new IllegalStateException("线程池已销毁。");
return this.runnableQueue.size();
}

@Override
public int getActiveCount() {
if (this.isShutdown)
throw new IllegalStateException("线程池已销毁。");
return this.activeCount;
}

线程池的应用

别测试线程池的任务提交、线程池线程数量的动态扩展,以 及线程池的销毁功能,代码如下所示。

package com.neu.day06;

import java.util.concurrent.TimeUnit;

public class ThreadPoolTest {

public static void main(String[] args) throws InterruptedException {
// 定义线程池,初始化线程数为 2,最大线程数为 6,核心线程数为 4,任务队列最多允许 1000 个任务
final ThreadPool threadPool = new BasicThreadPool(2, 6, 4, 1000);

// 定义 20 个任务并且提交给线程池
for (int i = 0; i < 20; i++) {
threadPool.execute(() -> {
try {
TimeUnit.SECONDS.sleep(10);
System.out.println(Thread.currentThread().getName() + " 正在运行。");
} catch (InterruptedException e) {
e.printStackTrace();
}
});
}

// 不断输出线程池的信息
while (true) {
System.out.println("threadPool.getActiveCount() = " + threadPool.getActiveCount());
System.out.println("threadPool.getQueueSize() = " + threadPool.getQueueSize());
System.out.println("threadPool.getCoreSize() = " + threadPool.getCoreSize());
System.out.println("threadPool.getMaxSize() = " + threadPool.getMaxSize());
System.out.println("-----------------------------------------------------------");
TimeUnit.SECONDS.sleep(5);
}
}

}

测试结果如下

上述测试代码中,定义了一个 Basic 线程池,其中初始化线程数量为 2,核心线程数量 为 4,最大线程数量为 6,最大任务队列数量为 1000,同时提交了 20 个任务到线程池中, 然后在 main 线程中不断地输出线程池中的线程数量信息监控变化,运行上述代码,截取的 部分输出信息如下:

"C:\Program Files\Java\jdk1.8.0_77\bin\java.exe" "-javaagent:D:\idea\idea2019\IntelliJ IDEA 2019.2.4\lib\idea_rt.jar=50206:D:\idea\idea2019\IntelliJ IDEA 2019.2.4\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files\java\jdk1.8.0_77\jre\lib\charsets.jar;C:\Program Files\java\jdk1.8.0_77\jre\lib\deploy.jar;C:\Program Files\java\jdk1.8.0_77\jre\lib\ext\access-bridge-64.jar;C:\Program Files\java\jdk1.8.0_77\jre\lib\ext\cldrdata.jar;C:\Program Files\java\jdk1.8.0_77\jre\lib\ext\dnsns.jar;C:\Program Files\java\jdk1.8.0_77\jre\lib\ext\jaccess.jar;C:\Program Files\java\jdk1.8.0_77\jre\lib\ext\jfxrt.jar;C:\Program Files\java\jdk1.8.0_77\jre\lib\ext\localedata.jar;C:\Program Files\java\jdk1.8.0_77\jre\lib\ext\nashorn.jar;C:\Program Files\java\jdk1.8.0_77\jre\lib\ext\sunec.jar;C:\Program Files\java\jdk1.8.0_77\jre\lib\ext\sunjce_provider.jar;C:\Program Files\java\jdk1.8.0_77\jre\lib\ext\sunmscapi.jar;C:\Program Files\java\jdk1.8.0_77\jre\lib\ext\sunpkcs11.jar;C:\Program Files\java\jdk1.8.0_77\jre\lib\ext\zipfs.jar;C:\Program Files\java\jdk1.8.0_77\jre\lib\javaws.jar;C:\Program Files\java\jdk1.8.0_77\jre\lib\jce.jar;C:\Program Files\java\jdk1.8.0_77\jre\lib\jfr.jar;C:\Program Files\java\jdk1.8.0_77\jre\lib\jfxswt.jar;C:\Program Files\java\jdk1.8.0_77\jre\lib\jsse.jar;C:\Program Files\java\jdk1.8.0_77\jre\lib\management-agent.jar;C:\Program Files\java\jdk1.8.0_77\jre\lib\plugin.jar;C:\Program Files\java\jdk1.8.0_77\jre\lib\resources.jar;C:\Program Files\java\jdk1.8.0_77\jre\lib\rt.jar;D:\javaSE\Practice01\01-Thread\target\classes" com.neu.day06.ThreadPoolTest
threadPool.getActiveCount() = 2
threadPool.getQueueSize() = 18
threadPool.getCoreSize() = 4
threadPool.getMaxSize() = 6
-----------------------------------------------------------
threadPool.getActiveCount() = 2
threadPool.getQueueSize() = 18
threadPool.getCoreSize() = 4
threadPool.getMaxSize() = 6
-----------------------------------------------------------
thread-pool-0 正在运行。
thread-pool-1 正在运行。
threadPool.getActiveCount() = 4
threadPool.getQueueSize() = 14
threadPool.getCoreSize() = 4
threadPool.getMaxSize() = 6
-----------------------------------------------------------
threadPool.getActiveCount() = 4
threadPool.getQueueSize() = 14
threadPool.getCoreSize() = 4
threadPool.getMaxSize() = 6
-----------------------------------------------------------
thread-pool-3 正在运行。
thread-pool-2 正在运行。
thread-pool-0 正在运行。
thread-pool-1 正在运行。
threadPool.getActiveCount() = 6
threadPool.getQueueSize() = 8
threadPool.getCoreSize() = 4
threadPool.getMaxSize() = 6
-----------------------------------------------------------
threadPool.getActiveCount() = 6
threadPool.getQueueSize() = 8
threadPool.getCoreSize() = 4
threadPool.getMaxSize() = 6
-----------------------------------------------------------
thread-pool-3 正在运行。
thread-pool-2 正在运行。
thread-pool-4 正在运行。
thread-pool-5 正在运行。
thread-pool-0 正在运行。
thread-pool-1 正在运行。
threadPool.getActiveCount() = 6
threadPool.getQueueSize() = 2
threadPool.getCoreSize() = 4
threadPool.getMaxSize() = 6
-----------------------------------------------------------
threadPool.getActiveCount() = 6
threadPool.getQueueSize() = 2
threadPool.getCoreSize() = 4
threadPool.getMaxSize() = 6
-----------------------------------------------------------
thread-pool-2 正在运行。
thread-pool-3 正在运行。
thread-pool-5 正在运行。
thread-pool-4 正在运行。
thread-pool-0 正在运行。
thread-pool-1 正在运行。
threadPool.getActiveCount() = 6
threadPool.getQueueSize() = 0
threadPool.getCoreSize() = 4
threadPool.getMaxSize() = 6
-----------------------------------------------------------
threadPool.getActiveCount() = 6
threadPool.getQueueSize() = 0
threadPool.getCoreSize() = 4
threadPool.getMaxSize() = 6
-----------------------------------------------------------
thread-pool-3 正在运行。
thread-pool-2 正在运行。
threadPool.getActiveCount() = 5
threadPool.getQueueSize() = 0
threadPool.getCoreSize() = 4
threadPool.getMaxSize() = 6
-----------------------------------------------------------
threadPool.getActiveCount() = 5
threadPool.getQueueSize() = 0
threadPool.getCoreSize() = 4
threadPool.getMaxSize() = 6
-----------------------------------------------------------
threadPool.getActiveCount() = 4
threadPool.getQueueSize() = 0
threadPool.getCoreSize() = 4
threadPool.getMaxSize() = 6
-----------------------------------------------------------
threadPool.getActiveCount() = 4
threadPool.getQueueSize() = 0
threadPool.getCoreSize() = 4
threadPool.getMaxSize() = 6
-----------------------------------------------------------
threadPool.getActiveCount() = 4
threadPool.getQueueSize() = 0
threadPool.getCoreSize() = 4
threadPool.getMaxSize() = 6
-----------------------------------------------------------
threadPool.getActiveCount() = 4
threadPool.getQueueSize() = 0
threadPool.getCoreSize() = 4
threadPool.getMaxSize() = 6
-----------------------------------------------------------
threadPool.getActiveCount() = 4
threadPool.getQueueSize() = 0
threadPool.getCoreSize() = 4
threadPool.getMaxSize() = 6
-----------------------------------------------------------
threadPool.getActiveCount() = 4
threadPool.getQueueSize() = 0
threadPool.getCoreSize() = 4
threadPool.getMaxSize() = 6
-----------------------------------------------------------
threadPool.getActiveCount() = 4
threadPool.getQueueSize() = 0
threadPool.getCoreSize() = 4
threadPool.getMaxSize() = 6
-----------------------------------------------------------
threadPool.getActiveCount() = 4
threadPool.getQueueSize() = 0
threadPool.getCoreSize() = 4
threadPool.getMaxSize() = 6
-----------------------------------------------------------
threadPool.getActiveCount() = 4
threadPool.getQueueSize() = 0
threadPool.getCoreSize() = 4
threadPool.getMaxSize() = 6
-----------------------------------------------------------
threadPool.getActiveCount() = 4
threadPool.getQueueSize() = 0
threadPool.getCoreSize() = 4
threadPool.getMaxSize() = 6
-----------------------------------------------------------
threadPool.getActiveCount() = 4
threadPool.getQueueSize() = 0
threadPool.getCoreSize() = 4
threadPool.getMaxSize() = 6
-----------------------------------------------------------
threadPool.getActiveCount() = 4
threadPool.getQueueSize() = 0
threadPool.getCoreSize() = 4
threadPool.getMaxSize() = 6
-----------------------------------------------------------
threadPool.getActiveCount() = 4
threadPool.getQueueSize() = 0
threadPool.getCoreSize() = 4
threadPool.getMaxSize() = 6
-----------------------------------------------------------
threadPool.getActiveCount() = 4
threadPool.getQueueSize() = 0
threadPool.getCoreSize() = 4
threadPool.getMaxSize() = 6
-----------------------------------------------------------
threadPool.getActiveCount() = 4
threadPool.getQueueSize() = 0
threadPool.getCoreSize() = 4
threadPool.getMaxSize() = 6
-----------------------------------------------------------
threadPool.getActiveCount() = 4
threadPool.getQueueSize() = 0
threadPool.getCoreSize() = 4
threadPool.getMaxSize() = 6
-----------------------------------------------------------
threadPool.getActiveCount() = 4
threadPool.getQueueSize() = 0
threadPool.getCoreSize() = 4
threadPool.getMaxSize() = 6
-----------------------------------------------------------

Process finished with exit code -1