总有人问线程池的问题 ?
于是就 专门写一篇,来讲讲 ThreadPoolExecutor
一、基础类和参数说明
/**
* Creates a new {@code ThreadPoolExecutor} with the given initial
* parameters.
*
* @param corePoolSize the number of threads to keep in the pool, even
* if they are idle, unless {@code allowCoreThreadTimeOut} is set
* @param maximumPoolSize the maximum number of threads to allow in the
* pool
* @param keepAliveTime when the number of threads is greater than
* the core, this is the maximum time that excess idle threads
* will wait for new tasks before terminating.
* @param unit the time unit for the {@code keepAliveTime} argument
* @param workQueue the queue to use for holding tasks before they are
* executed. This queue will hold only the {@code Runnable}
* tasks submitted by the {@code execute} method.
* @param threadFactory the factory to use when the executor
* creates a new thread
* @param handler the handler to use when execution is blocked
* because the thread bounds and queue capacities are reached
* @throws IllegalArgumentException if one of the following holds:<br>
* {@code corePoolSize < 0}<br>
* {@code keepAliveTime < 0}<br>
* {@code maximumPoolSize <= 0}<br>
* {@code maximumPoolSize < corePoolSize}
* @throws NullPointerException if {@code workQueue}
* or {@code threadFactory} or {@code handler} is null
*/
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;
}
1.corePoolSize:该线程池中核心线程数最大值
2.maximumPoolSize: 该线程池中线程总数最大值
3.keepAliveTime:该线程池中非核心线程闲置超时时长,过了这个时间会被回收,并且不会再被创建出来。
4.unit:keepAliveTime的单位
5.workQueue:阻塞队列BlockingQueue,维护着等待执行的Runnable对象
workQueue有4中类型:常用的有ArrayBlockingQueue和LinkedBlockingQueue,后两种基本不用。
5.1ArrayBlockingQueue:基于数组结构的有界阻塞队列,构造函数一定要传大小,FIFO(先进先出);
5.2LinkedBlockingQueue:无界,默认大小65536(Integer.MAX_VALUE),当大量请求任务时,容易造成内存耗尽。5.3SynchronousQueue:同步队列,是一个特殊的BlockingQueue,它没有容量(这是因为在SynchronousQueue中,插入将等待另一个线程的删除操作,反之亦然)。具体可以参考:《Java SynchronousQueue Examples(译)》
4.4PriorityBlockingQueue: 优先队列,无界。
5.5 DelayedWorkQueue:这个队列接收到任务时,首先先入队,只有达到了指定的延时时间,才会执行任务阻塞队列常见的方法如下表所示:
6.threadFactory:创建线程的接口,需要实现他的Thread newThread(Runnable r)方法。
7.RejectedExecutionHandler:饱和策略,最大线程和工作队列容量且已经饱和时execute方法都将调用RejectedExecutionHandler
二、工作方式(结论)
workQueue 选择不同,处理方式也不同,只列举出来两个常用的
workQueue方式 | 情景条件 | 处理方式 |
ArrayBlockingQueue | 1.任务数<=核心线程数corePoolSize
2.maximumPoolSize>=任务数>核心线程数corePoolSize 2.1 任务数<=核心线程数corePoolSize + ArrayBlockingQueue指定长度
2.2 任务数>核心线程数corePoolSize + ArrayBlockingQueue指定长度
3.任务数>maximumPoolSize
| 1.直接用核心线程执行 2.1 使用核心线程数,超出部分放到队列中等待顺序执行 2.2 已经超出了队列长度的部分,新建线程执行,最终将线程数最大扩容到maximumPoolSize这个等级,此时同时运行的线程最多有maximumPoolSize个线程在运行 3.如果瞬间加入的任务数大于maximumPoolSize,则超出部分会执行饱和策略,默认为拒绝抛异常 |
LinkedBlockingQueue | 任务数小于、大于、等于核心线程数corePoolSize
| 由于队列无界,所以处理方式相对简单:最多用核心线程数corePoolSize个线程执行任务,超过的任务放入LinkedBlockingQueue队列中,等待核心线程释放资源后,排队执行 |
三、测试代码
package com;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import java.text.DateFormat;
import java.text.MessageFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.*;
public class ThreadPoolTest {
private static Executor executor = null;
//线程池缓冲队列
private static LinkedBlockingQueue<Runnable> workQueue = null;
//当线程池中的线程数目达到corePoolSize后,就会把到达的任务放到缓存队列当中
private static int COREPOOLSIZE = 2;
// 最多有这么多个线程,使用ArrayBlockingQueue阻塞队列时,这个值会生效
private static int MAXIMUMPOOLSIZE = 3;
public static void main(String[] args) throws InterruptedException {
//一下为执行例子,执行结果在具体方法中
//1.向线程池中添加任务,当任务数量少于corePoolSize时,会自动创建thead来处理这些任务;
testLtCorePoolSize();
//2.当添加任务数大于COREPOOLSIZE且少于MAXIMUMPOOLSIZE时,MAXIMUMPOOLSIZE参数理论上会失效。。
// 2.1如果创建的workQueue是为LinkedBlockingQueue(无需指定长度,自动扩容,但是实际使用过程中有可能会内存溢出)类型
// 2.1.1当添加任务数大于COREPOOLSIZE且少于MAXIMUMPOOLSIZE时,会把这些任务放到workQueue,等待执行
testLinkedBlockingQueueGtCorePoolSizeAndLtMaximumpoolize();
// 2.1.2 当添加任务数大于MAXIMUMPOOLSIZE时,会把这些任务放到workQueue,等待执行,跟2.1中没啥区别。
testLinkedBlockingQueueGtMaximumpoolize();
// 2.2如果创建的workQueue是为ArrayBlockingQueue类型(这个类型的队列必须指定长度)
// 2.2.1如果(任务数N)-COREPOOLSIZE <= ArrayBlockingQueue的指定长度,情况与2.1.1相同,等待执行即可(这个没有例子看,跟2.1.1,2.2.2一样的,没啥区别)
// 2.2.2(任务数N)-COREPOOLSIZE > ArrayBlockingQueue的指定长度,会新创建(任务数N)-COREPOOLSIZE个线程进行执行;
testArrayBlockingQueueGtBlockQueueSizeAndLtMaximumpoolsize();
//3.任务数>MAXIMUMPOOLSIZE,
// 3.1workQueue是ArrayBlockingQueue类型的,都会根据拒绝策略进行处理,默认是抛异常,拒绝
testArrayBlockingQueueGtMaximumpoolsize();
// 3.2workQueue是LinkedBlockingQueue类型的,这个会放到缓冲队列中,,默默消费,不会报异常的
testLinkedBlockingQueueGtMaximumpoolsize();
//任务数>MAXIMUMPOOLSIZE workQueue是ArrayBlockingQueue类型的,我们测试下keepAliveTime参数是干嘛的
// 结论是 任务数>COREPOOLSIZE 之后的创建的MAXIMUMPOOLSIZE-COREPOOLSIZE这些线程相当于是借的,如果空闲等待时间超过keepAliveTime,会直接被回收。这些线程相当于是借的,还了就没了,以后不会再创建了
testArrayBlockingQueueAliveTime();
}
/**
*
*
*/
private static void testLtCorePoolSize() throws InterruptedException {
workQueue = new LinkedBlockingQueue<>();
executor = new ThreadPoolExecutor(COREPOOLSIZE,
MAXIMUMPOOLSIZE,
60,
TimeUnit.SECONDS,
workQueue,
new ThreadFactoryBuilder().setDaemon(true).setNameFormat("ThreadPoolTest-%d").build());
for (int i = 0;i< COREPOOLSIZE; i ++) {
executor.execute(new TestThread(1000));
}
// 主线程休眠10s以观察情况
Thread.sleep(10000);
// 以下为这个方法运行完的结果,我们可以得出结论:
// 向线程池中添加任务,当任务数量少于corePoolSize时,会自动创建thead来处理这些任务;
/**
* 2020-06-18 18:17:55.27线程ThreadPoolTest-0启动
* 2020-06-18 18:17:55.27线程ThreadPoolTest-1启动
* 2020-06-18 18:17:55.28线程ThreadPoolTest-1执行中进行1阶段
* 2020-06-18 18:17:55.28线程ThreadPoolTest-0执行中进行1阶段
* 2020-06-18 18:17:55.230线程ThreadPoolTest-0执行中进行2阶段
* 2020-06-18 18:17:55.230线程ThreadPoolTest-1执行中进行2阶段
* 2020-06-18 18:17:55.431线程ThreadPoolTest-0执行中进行3阶段
* 2020-06-18 18:17:55.431线程ThreadPoolTest-1执行中进行3阶段
* 2020-06-18 18:17:55.634线程ThreadPoolTest-1执行中进行4阶段
* 2020-06-18 18:17:55.634线程ThreadPoolTest-0执行中进行4阶段
* 2020-06-18 18:17:55.838线程ThreadPoolTest-0执行中进行5阶段
* 2020-06-18 18:17:55.838线程ThreadPoolTest-1执行中进行5阶段
* 2020-06-18 18:17:56.42线程ThreadPoolTest-1结束
* 2020-06-18 18:17:56.42线程ThreadPoolTest-0结束
*/
}
/**
* 2.1.1 当添加任务数大于COREPOOLSIZE且少于MAXIMUMPOOLSIZE时,MAXIMUMPOOLSIZE参数理论上会失效。。
* 如果创建的workQueue是为LinkedBlockingQueue(无需指定长度,自动扩容,但是实际使用过程中有可能会内存溢出)类型,会把这些任务放到workQueue,等待执行
* @throws InterruptedException
*/
private static void testLinkedBlockingQueueGtCorePoolSizeAndLtMaximumpoolize() throws InterruptedException {
workQueue = new LinkedBlockingQueue<>();
COREPOOLSIZE = 2;
MAXIMUMPOOLSIZE = 4;
executor = new ThreadPoolExecutor(COREPOOLSIZE,
MAXIMUMPOOLSIZE,
60,
TimeUnit.SECONDS,
workQueue,
new ThreadFactoryBuilder().setDaemon(true).setNameFormat("ThreadPoolTest-%d").build());
for (int i = 0; i < MAXIMUMPOOLSIZE; i++) {
executor.execute(new TestThread(1000));
}
// 主线程休眠10s以观察情况
Thread.sleep(10000);
/**
* 以下为这个方法运行完的结果,
* 2020-06-18 18:29:30.517线程ThreadPoolTest-0启动
* 2020-06-18 18:29:30.517线程ThreadPoolTest-1启动
* 2020-06-18 18:29:30.518线程ThreadPoolTest-0执行中进行1阶段
* 2020-06-18 18:29:30.518线程ThreadPoolTest-1执行中进行1阶段
* 2020-06-18 18:29:30.722线程ThreadPoolTest-1执行中进行2阶段
* 2020-06-18 18:29:30.722线程ThreadPoolTest-0执行中进行2阶段
* 2020-06-18 18:29:30.924线程ThreadPoolTest-1执行中进行3阶段
* 2020-06-18 18:29:30.924线程ThreadPoolTest-0执行中进行3阶段
* 2020-06-18 18:29:31.126线程ThreadPoolTest-1执行中进行4阶段
* 2020-06-18 18:29:31.126线程ThreadPoolTest-0执行中进行4阶段
* 2020-06-18 18:29:31.330线程ThreadPoolTest-0执行中进行5阶段
* 2020-06-18 18:29:31.330线程ThreadPoolTest-1执行中进行5阶段
* 2020-06-18 18:29:31.533线程ThreadPoolTest-0结束
* 2020-06-18 18:29:31.533线程ThreadPoolTest-1结束
*
* 注意看 下面的线程名字根本没有发生变化,所以并没有创建新的线程,而是复用了 ThreadPoolTest-0 -1线程
* 2020-06-18 18:29:31.533线程ThreadPoolTest-0启动
* 2020-06-18 18:29:31.533线程ThreadPoolTest-1启动
* 2020-06-18 18:29:31.533线程ThreadPoolTest-0执行中进行1阶段
* 2020-06-18 18:29:31.533线程ThreadPoolTest-1执行中进行1阶段
* 2020-06-18 18:29:31.735线程ThreadPoolTest-1执行中进行2阶段
* 2020-06-18 18:29:31.735线程ThreadPoolTest-0执行中进行2阶段
* 2020-06-18 18:29:31.937线程ThreadPoolTest-0执行中进行3阶段
* 2020-06-18 18:29:31.938线程ThreadPoolTest-1执行中进行3阶段
* 2020-06-18 18:29:32.139线程ThreadPoolTest-1执行中进行4阶段
* 2020-06-18 18:29:32.139线程ThreadPoolTest-0执行中进行4阶段
* 2020-06-18 18:29:32.344线程ThreadPoolTest-0执行中进行5阶段
* 2020-06-18 18:29:32.344线程ThreadPoolTest-1执行中进行5阶段
* 2020-06-18 18:29:32.544线程ThreadPoolTest-1结束
* 2020-06-18 18:29:32.544线程ThreadPoolTest-0结束
*/
}
/**
* 2.1.2 当添加任务数大于MAXIMUMPOOLSIZE时,MAXIMUMPOOLSIZE参数理论上会失效。。
* 如果创建的workQueue是为LinkedBlockingQueue类型,会把这些任务放到workQueue,等待执行,跟2.1中没啥区别。。
* @throws InterruptedException
*/
private static void testLinkedBlockingQueueGtMaximumpoolize() throws InterruptedException {
workQueue = new LinkedBlockingQueue<>();
COREPOOLSIZE = 2;
MAXIMUMPOOLSIZE = 4;
executor = new ThreadPoolExecutor(COREPOOLSIZE,
MAXIMUMPOOLSIZE,
60,
TimeUnit.SECONDS,
workQueue,
new ThreadFactoryBuilder().setDaemon(true).setNameFormat("ThreadPoolTest-%d").build());
for (int i = 0; i < MAXIMUMPOOLSIZE + 2; i++) {
executor.execute(new TestThread(1000));
}
// 主线程休眠10s以观察情况
Thread.sleep(10000);
/**
* 以下为这个方法运行完的结果,
2020-06-18 20:41:32.384线程ThreadPoolTest-1启动
2020-06-18 20:41:32.384线程ThreadPoolTest-0启动
2020-06-18 20:41:32.385线程ThreadPoolTest-1执行中进行1阶段
2020-06-18 20:41:32.385线程ThreadPoolTest-0执行中进行1阶段
2020-06-18 20:41:32.588线程ThreadPoolTest-1执行中进行2阶段
2020-06-18 20:41:32.588线程ThreadPoolTest-0执行中进行2阶段
2020-06-18 20:41:32.791线程ThreadPoolTest-1执行中进行3阶段
2020-06-18 20:41:32.791线程ThreadPoolTest-0执行中进行3阶段
2020-06-18 20:41:32.994线程ThreadPoolTest-1执行中进行4阶段
2020-06-18 20:41:32.994线程ThreadPoolTest-0执行中进行4阶段
2020-06-18 20:41:33.198线程ThreadPoolTest-0执行中进行5阶段
2020-06-18 20:41:33.198线程ThreadPoolTest-1执行中进行5阶段
2020-06-18 20:41:33.399线程ThreadPoolTest-0结束
2020-06-18 20:41:33.399线程ThreadPoolTest-1结束
安安静静的等待核心的两个线程执行完,然后开启下一轮切换
2020-06-18 20:41:33.400线程ThreadPoolTest-1启动
2020-06-18 20:41:33.400线程ThreadPoolTest-0启动
2020-06-18 20:41:33.400线程ThreadPoolTest-1执行中进行1阶段
2020-06-18 20:41:33.400线程ThreadPoolTest-0执行中进行1阶段
2020-06-18 20:41:33.603线程ThreadPoolTest-1执行中进行2阶段
2020-06-18 20:41:33.604线程ThreadPoolTest-0执行中进行2阶段
2020-06-18 20:41:33.805线程ThreadPoolTest-0执行中进行3阶段
2020-06-18 20:41:33.805线程ThreadPoolTest-1执行中进行3阶段
2020-06-18 20:41:34.8线程ThreadPoolTest-0执行中进行4阶段
2020-06-18 20:41:34.8线程ThreadPoolTest-1执行中进行4阶段
2020-06-18 20:41:34.213线程ThreadPoolTest-1执行中进行5阶段
2020-06-18 20:41:34.213线程ThreadPoolTest-0执行中进行5阶段
2020-06-18 20:41:34.414线程ThreadPoolTest-1结束
2020-06-18 20:41:34.414线程ThreadPoolTest-0结束
安安静静的等待核心的两个线程执行完,然后开启下一轮切换
2020-06-18 20:41:34.414线程ThreadPoolTest-1启动
2020-06-18 20:41:34.414线程ThreadPoolTest-0启动
2020-06-18 20:41:34.415线程ThreadPoolTest-1执行中进行1阶段
2020-06-18 20:41:34.415线程ThreadPoolTest-0执行中进行1阶段
2020-06-18 20:41:34.619线程ThreadPoolTest-1执行中进行2阶段
2020-06-18 20:41:34.619线程ThreadPoolTest-0执行中进行2阶段
2020-06-18 20:41:34.823线程ThreadPoolTest-0执行中进行3阶段
2020-06-18 20:41:34.823线程ThreadPoolTest-1执行中进行3阶段
2020-06-18 20:41:35.27线程ThreadPoolTest-0执行中进行4阶段
2020-06-18 20:41:35.27线程ThreadPoolTest-1执行中进行4阶段
2020-06-18 20:41:35.230线程ThreadPoolTest-0执行中进行5阶段
2020-06-18 20:41:35.230线程ThreadPoolTest-1执行中进行5阶段
2020-06-18 20:41:35.432线程ThreadPoolTest-0结束
2020-06-18 20:41:35.432线程ThreadPoolTest-1结束
*/
}
/**
* 2.2当添加(任务数N)大于COREPOOLSIZE且少于MAXIMUMPOOLSIZE,
* 如果创建的workQueue是为ArrayBlockingQueue类型(这个类型的队列必须指定长度),
* 2.2.1如果(任务数N)-COREPOOLSIZE <= ArrayBlockingQueue的指定长度,情况与2.1.1相同,等待执行即可
* 2.2.2(任务数N)-COREPOOLSIZE > ArrayBlockingQueue的指定长度,会新创建(任务数N)-COREPOOLSIZE个线程进行执行;
*
* 这个测试方法就只是实现2.2.2而已
* @throws InterruptedException
*/
private static void testArrayBlockingQueueGtBlockQueueSizeAndLtMaximumpoolsize() throws InterruptedException {
// 设置阻塞队列,并且限定长度,从而触发创建thread的操作
ArrayBlockingQueue workQueue = new ArrayBlockingQueue<Integer>(1);
COREPOOLSIZE = 2;
MAXIMUMPOOLSIZE = 6;
executor = new ThreadPoolExecutor(COREPOOLSIZE,
MAXIMUMPOOLSIZE,
60,
TimeUnit.SECONDS,
workQueue,
new ThreadFactoryBuilder().setDaemon(true).setNameFormat("ThreadPoolTest-%d").build());
for (int i = 0; i < 5; i++) {
// sleep一下看的结果更加明显
Thread.sleep(20);
executor.execute(new TestThread(1000));
}
// 主线程休眠10s以观察情况
Thread.sleep(10000);
/**
* 一共有5个线程,2个核心线程ThreadPoolTest-0-1在执行,1个放到了workQueue阻塞队列里,由于阻塞队里满了,
* 所以2个又直接启动了线程ThreadPoolTest-2,ThreadPoolTest-3执行。
*
2020-06-18 21:10:27.568线程ThreadPoolTest-0启动
2020-06-18 21:10:27.568线程ThreadPoolTest-0执行中进行1阶段
2020-06-18 21:10:27.591线程ThreadPoolTest-1启动
2020-06-18 21:10:27.591线程ThreadPoolTest-1执行中进行1阶段
2020-06-18 21:10:27.637线程ThreadPoolTest-2启动
2020-06-18 21:10:27.638线程ThreadPoolTest-2执行中进行1阶段
2020-06-18 21:10:27.660线程ThreadPoolTest-3启动
2020-06-18 21:10:27.660线程ThreadPoolTest-3执行中进行1阶段
2020-06-18 21:10:27.771线程ThreadPoolTest-0执行中进行2阶段
2020-06-18 21:10:27.794线程ThreadPoolTest-1执行中进行2阶段
2020-06-18 21:10:27.842线程ThreadPoolTest-2执行中进行2阶段
2020-06-18 21:10:27.861线程ThreadPoolTest-3执行中进行2阶段
2020-06-18 21:10:27.972线程ThreadPoolTest-0执行中进行3阶段
2020-06-18 21:10:27.995线程ThreadPoolTest-1执行中进行3阶段
2020-06-18 21:10:28.44线程ThreadPoolTest-2执行中进行3阶段
2020-06-18 21:10:28.64线程ThreadPoolTest-3执行中进行3阶段
2020-06-18 21:10:28.175线程ThreadPoolTest-0执行中进行4阶段
2020-06-18 21:10:28.196线程ThreadPoolTest-1执行中进行4阶段
2020-06-18 21:10:28.248线程ThreadPoolTest-2执行中进行4阶段
2020-06-18 21:10:28.268线程ThreadPoolTest-3执行中进行4阶段
2020-06-18 21:10:28.382线程ThreadPoolTest-0执行中进行5阶段
2020-06-18 21:10:28.401线程ThreadPoolTest-1执行中进行5阶段
2020-06-18 21:10:28.450线程ThreadPoolTest-2执行中进行5阶段
2020-06-18 21:10:28.470线程ThreadPoolTest-3执行中进行5阶段
2020-06-18 21:10:28.586线程ThreadPoolTest-0结束
2020-06-18 21:10:28.586线程ThreadPoolTest-0启动
2020-06-18 21:10:28.586线程ThreadPoolTest-0执行中进行1阶段
2020-06-18 21:10:28.602线程ThreadPoolTest-1结束
2020-06-18 21:10:28.654线程ThreadPoolTest-2结束
2020-06-18 21:10:28.671线程ThreadPoolTest-3结束
workQueue阻塞队列里的那个等核心线程结束了任务,就重新放进去执行。
2020-06-18 21:10:28.791线程ThreadPoolTest-0执行中进行2阶段
2020-06-18 21:10:28.997线程ThreadPoolTest-0执行中进行3阶段
2020-06-18 21:10:29.199线程ThreadPoolTest-0执行中进行4阶段
2020-06-18 21:10:29.404线程ThreadPoolTest-0执行中进行5阶段
2020-06-18 21:10:29.609线程ThreadPoolTest-0结束
*/
}
/**
* 3.任务数>MAXIMUMPOOLSIZE,
* 3.1workQueue是ArrayBlockingQueue类型的,都会根据拒绝策略进行处理,默认是抛异常,拒绝
*/
private static void testArrayBlockingQueueGtMaximumpoolsize() throws InterruptedException {
ArrayBlockingQueue workQueue = new ArrayBlockingQueue<Integer>(1);
COREPOOLSIZE = 2;
MAXIMUMPOOLSIZE = 2;
executor = new ThreadPoolExecutor(COREPOOLSIZE,
MAXIMUMPOOLSIZE,
60,
TimeUnit.SECONDS,
workQueue,
new ThreadFactoryBuilder().setDaemon(true).setNameFormat("ThreadPoolTest-%d").build());
for (int i = 0; i < MAXIMUMPOOLSIZE +2; i++) {
try {
executor.execute(new TestThread(1000));
} catch (Exception e) {
e.printStackTrace();
}
}
// 主线程休眠10s以观察情况
Thread.sleep(10000);
/**
*
2020-06-18 21:20:16.787线程ThreadPoolTest-0启动
2020-06-18 21:20:16.787线程ThreadPoolTest-1启动
2020-06-18 21:20:16.788线程ThreadPoolTest-0执行中进行1阶段
2020-06-18 21:20:16.788线程ThreadPoolTest-1执行中进行1阶段
超过了
java.util.concurrent.RejectedExecutionException: Task com.qlchat.ThreadPoolTest$TestThread@4ddced80 rejected from java.util.concurrent.ThreadPoolExecutor@1534f01b[Running, pool size = 2, active threads = 2, queued tasks = 1, completed tasks = 0]
at java.util.concurrent.ThreadPoolExecutor$AbortPolicy.rejectedExecution(ThreadPoolExecutor.java:2063)
at java.util.concurrent.ThreadPoolExecutor.reject(ThreadPoolExecutor.java:830)
at java.util.concurrent.ThreadPoolExecutor.execute(ThreadPoolExecutor.java:1379)
at com.qlchat.ThreadPoolTest.testGtMaximumpoolsize(ThreadPoolTest.java:288)
at com.qlchat.ThreadPoolTest.main(ThreadPoolTest.java:34)
2020-06-18 21:20:16.989线程ThreadPoolTest-1执行中进行2阶段
2020-06-18 21:20:16.989线程ThreadPoolTest-0执行中进行2阶段
2020-06-18 21:20:17.194线程ThreadPoolTest-0执行中进行3阶段
2020-06-18 21:20:17.194线程ThreadPoolTest-1执行中进行3阶段
2020-06-18 21:20:17.398线程ThreadPoolTest-1执行中进行4阶段
2020-06-18 21:20:17.398线程ThreadPoolTest-0执行中进行4阶段
2020-06-18 21:20:17.599线程ThreadPoolTest-1执行中进行5阶段
2020-06-18 21:20:17.599线程ThreadPoolTest-0执行中进行5阶段
2020-06-18 21:20:17.802线程ThreadPoolTest-0结束
2020-06-18 21:20:17.802线程ThreadPoolTest-1结束
2020-06-18 21:20:17.802线程ThreadPoolTest-0启动
2020-06-18 21:20:17.803线程ThreadPoolTest-0执行中进行1阶段
2020-06-18 21:20:18.5线程ThreadPoolTest-0执行中进行2阶段
2020-06-18 21:20:18.211线程ThreadPoolTest-0执行中进行3阶段
2020-06-18 21:20:18.412线程ThreadPoolTest-0执行中进行4阶段
2020-06-18 21:20:18.617线程ThreadPoolTest-0执行中进行5阶段
2020-06-18 21:20:18.821线程ThreadPoolTest-0结束
*/
}
/**
* 3.任务数>MAXIMUMPOOLSIZE,
* 3.2workQueue是LinkedBlockingQueue类型的,这个会放到缓冲队列中,,默默消费,不会报异常的
*/
private static void testLinkedBlockingQueueGtMaximumpoolsize() throws InterruptedException {
LinkedBlockingQueue workQueue = new LinkedBlockingQueue<>();
COREPOOLSIZE = 2;
MAXIMUMPOOLSIZE = 2;
executor = new ThreadPoolExecutor(COREPOOLSIZE,
MAXIMUMPOOLSIZE,
60,
TimeUnit.SECONDS,
workQueue,
new ThreadFactoryBuilder().setDaemon(true).setNameFormat("ThreadPoolTest-%d").build());
for (int i = 0; i < MAXIMUMPOOLSIZE +2; i++) {
try {
executor.execute(new TestThread(1000));
} catch (Exception e) {
e.printStackTrace();
}
}
// 主线程休眠10s以观察情况
Thread.sleep(10000);
/**
* 2020-06-18 21:24:20.731线程ThreadPoolTest-1启动
* 2020-06-18 21:24:20.731线程ThreadPoolTest-0启动
* 2020-06-18 21:24:20.732线程ThreadPoolTest-0执行中进行1阶段
* 2020-06-18 21:24:20.732线程ThreadPoolTest-1执行中进行1阶段
* 2020-06-18 21:24:20.932线程ThreadPoolTest-0执行中进行2阶段
* 2020-06-18 21:24:20.936线程ThreadPoolTest-1执行中进行2阶段
* 2020-06-18 21:24:21.135线程ThreadPoolTest-0执行中进行3阶段
* 2020-06-18 21:24:21.140线程ThreadPoolTest-1执行中进行3阶段
* 2020-06-18 21:24:21.338线程ThreadPoolTest-0执行中进行4阶段
* 2020-06-18 21:24:21.346线程ThreadPoolTest-1执行中进行4阶段
* 2020-06-18 21:24:21.543线程ThreadPoolTest-0执行中进行5阶段
* 2020-06-18 21:24:21.550线程ThreadPoolTest-1执行中进行5阶段
* 2020-06-18 21:24:21.744线程ThreadPoolTest-0结束
* 2020-06-18 21:24:21.744线程ThreadPoolTest-0启动
* 2020-06-18 21:24:21.745线程ThreadPoolTest-0执行中进行1阶段
* 2020-06-18 21:24:21.754线程ThreadPoolTest-1结束
* 2020-06-18 21:24:21.755线程ThreadPoolTest-1启动
* 2020-06-18 21:24:21.756线程ThreadPoolTest-1执行中进行1阶段
* 2020-06-18 21:24:21.950线程ThreadPoolTest-0执行中进行2阶段
* 2020-06-18 21:24:21.962线程ThreadPoolTest-1执行中进行2阶段
* 2020-06-18 21:24:22.154线程ThreadPoolTest-0执行中进行3阶段
* 2020-06-18 21:24:22.164线程ThreadPoolTest-1执行中进行3阶段
* 2020-06-18 21:24:22.356线程ThreadPoolTest-0执行中进行4阶段
* 2020-06-18 21:24:22.367线程ThreadPoolTest-1执行中进行4阶段
* 2020-06-18 21:24:22.561线程ThreadPoolTest-0执行中进行5阶段
* 2020-06-18 21:24:22.572线程ThreadPoolTest-1执行中进行5阶段
* 2020-06-18 21:24:22.766线程ThreadPoolTest-0结束
* 2020-06-18 21:24:22.777线程ThreadPoolTest-1结束
*/
}
/**
* 4.任务数>MAXIMUMPOOLSIZEworkQueue是ArrayBlockingQueue类型的,我们测试下keepAliveTime参数是干嘛的
*/
private static void testArrayBlockingQueueAliveTime() throws InterruptedException {
ArrayBlockingQueue workQueue = new ArrayBlockingQueue<Integer>(1);
COREPOOLSIZE = 2;
MAXIMUMPOOLSIZE = 4;
executor = new ThreadPoolExecutor(COREPOOLSIZE,
MAXIMUMPOOLSIZE,
10,
TimeUnit.MILLISECONDS,
workQueue,
new ThreadFactoryBuilder().setDaemon(true).setNameFormat("ThreadPoolTest-%d").build());
for (int i = 0; i < COREPOOLSIZE; i++) {
try {
executor.execute(new TestThread(5000, "coreThread" + i));
} catch (Exception e) {
e.printStackTrace();
}
}
for (int i = 0; i < 1; i++) {
try {
executor.execute(new TestThread(5000, "workQueueThread" + i));
} catch (Exception e) {
e.printStackTrace();
}
}
for (int i = 0; i < 4; i++) {
try {
Thread.sleep(100);
System.out.println(getNow() + "put maximumpoolThread" + i);
executor.execute(new TestThread(20, "maximumpoolThread" + i));
} catch (Exception e) {
e.printStackTrace();
}
}
// 主线程休眠10s以观察情况
Thread.sleep(20000);
/**
* 2020-06-19 10:15:28.878线程ThreadPoolTest-1:coreThread1启动
* 2020-06-19 10:15:28.878线程ThreadPoolTest-0:coreThread0启动
* 2020-06-19 10:15:28.884线程ThreadPoolTest-1:coreThread1执行中进行1阶段
* 2020-06-19 10:15:28.884线程ThreadPoolTest-0:coreThread0执行中进行1阶段
* 2020-06-19 10:15:28.963put maximumpoolThread0
* 2020-06-19 10:15:28.964线程ThreadPoolTest-2:maximumpoolThread0启动
* 2020-06-19 10:15:28.964线程ThreadPoolTest-2:maximumpoolThread0执行中进行1阶段
* 2020-06-19 10:15:28.969线程ThreadPoolTest-2:maximumpoolThread0执行中进行2阶段
* 2020-06-19 10:15:28.974线程ThreadPoolTest-2:maximumpoolThread0执行中进行3阶段
* 2020-06-19 10:15:28.979线程ThreadPoolTest-2:maximumpoolThread0执行中进行4阶段
* 2020-06-19 10:15:28.985线程ThreadPoolTest-2:maximumpoolThread0执行中进行5阶段
* 2020-06-19 10:15:28.990线程ThreadPoolTest-2:maximumpoolThread0结束
* 2020-06-19 10:15:28.990线程ThreadPoolTest-2:workQueueThread0启动
* 2020-06-19 10:15:28.990线程ThreadPoolTest-2:workQueueThread0执行中进行1阶段
* 2020-06-19 10:15:29.67put maximumpoolThread1
* 2020-06-19 10:15:29.171put maximumpoolThread2
* 2020-06-19 10:15:29.171线程ThreadPoolTest-3:maximumpoolThread2启动
* 2020-06-19 10:15:29.172线程ThreadPoolTest-3:maximumpoolThread2执行中进行1阶段
* 2020-06-19 10:15:29.177线程ThreadPoolTest-3:maximumpoolThread2执行中进行2阶段
* 2020-06-19 10:15:29.183线程ThreadPoolTest-3:maximumpoolThread2执行中进行3阶段
* 2020-06-19 10:15:29.188线程ThreadPoolTest-3:maximumpoolThread2执行中进行4阶段
* 2020-06-19 10:15:29.193线程ThreadPoolTest-3:maximumpoolThread2执行中进行5阶段
* 2020-06-19 10:15:29.198线程ThreadPoolTest-3:maximumpoolThread2结束
* 2020-06-19 10:15:29.198线程ThreadPoolTest-3:maximumpoolThread1启动
* 2020-06-19 10:15:29.199线程ThreadPoolTest-3:maximumpoolThread1执行中进行1阶段
* 2020-06-19 10:15:29.204线程ThreadPoolTest-3:maximumpoolThread1执行中进行2阶段
* 2020-06-19 10:15:29.209线程ThreadPoolTest-3:maximumpoolThread1执行中进行3阶段
* 2020-06-19 10:15:29.214线程ThreadPoolTest-3:maximumpoolThread1执行中进行4阶段
* 2020-06-19 10:15:29.219线程ThreadPoolTest-3:maximumpoolThread1执行中进行5阶段
* 2020-06-19 10:15:29.224线程ThreadPoolTest-3:maximumpoolThread1结束
*
* 注意观察这里,put进去了maximumpoolThread3,但是由于ThreadPoolTest-3 过了keepAliveTime时间10ms,被回收了。
* 所以就算put进去,,只能等到其他线程有空的时候执行
* 2020-06-19 10:15:29.271put maximumpoolThread3
* 2020-06-19 10:15:29.889线程ThreadPoolTest-1:coreThread1执行中进行2阶段
* 2020-06-19 10:15:29.889线程ThreadPoolTest-0:coreThread0执行中进行2阶段
* 2020-06-19 10:15:29.992线程ThreadPoolTest-2:workQueueThread0执行中进行2阶段
* 2020-06-19 10:15:30.891线程ThreadPoolTest-0:coreThread0执行中进行3阶段
* 2020-06-19 10:15:30.891线程ThreadPoolTest-1:coreThread1执行中进行3阶段
* 2020-06-19 10:15:30.994线程ThreadPoolTest-2:workQueueThread0执行中进行3阶段
* 2020-06-19 10:15:31.894线程ThreadPoolTest-0:coreThread0执行中进行4阶段
* 2020-06-19 10:15:31.894线程ThreadPoolTest-1:coreThread1执行中进行4阶段
* 2020-06-19 10:15:31.999线程ThreadPoolTest-2:workQueueThread0执行中进行4阶段
* 2020-06-19 10:15:32.899线程ThreadPoolTest-0:coreThread0执行中进行5阶段
* 2020-06-19 10:15:32.899线程ThreadPoolTest-1:coreThread1执行中进行5阶段
* 2020-06-19 10:15:33.0线程ThreadPoolTest-2:workQueueThread0执行中进行5阶段
* 2020-06-19 10:15:33.901线程ThreadPoolTest-0:coreThread0结束
* 2020-06-19 10:15:33.901线程ThreadPoolTest-1:coreThread1结束
* maximumpoolThread3被ThreadPoolTest-0 执行
* 2020-06-19 10:15:33.901线程ThreadPoolTest-0:maximumpoolThread3启动
* 2020-06-19 10:15:33.901线程ThreadPoolTest-0:maximumpoolThread3执行中进行1阶段
* 2020-06-19 10:15:33.907线程ThreadPoolTest-0:maximumpoolThread3执行中进行2阶段
* 2020-06-19 10:15:33.913线程ThreadPoolTest-0:maximumpoolThread3执行中进行3阶段
* 2020-06-19 10:15:33.918线程ThreadPoolTest-0:maximumpoolThread3执行中进行4阶段
* 2020-06-19 10:15:33.924线程ThreadPoolTest-0:maximumpoolThread3执行中进行5阶段
* 2020-06-19 10:15:33.929线程ThreadPoolTest-0:maximumpoolThread3结束
* 2020-06-19 10:15:34.1线程ThreadPoolTest-2:workQueueThread0结束
*/
}
static class TestThread implements Runnable {
//执行时间,单位是毫秒
private Integer runTime = null;
//为了便于观察线程执行过程,分5次打印
private Integer step = 5;
private String name = null;
public TestThread(Integer runTime, String name) {
this.runTime = runTime;
this.name = name;
}
public TestThread(Integer runTime) {
this.runTime = runTime;
}
@Override
public void run() {
String threadName = name == null ? Thread.currentThread().getName() : Thread.currentThread().getName() + ":" + name;
System.out.println(MessageFormat.format("{0}线程{1}启动",getNow(), threadName));
try {
for (int i = 0; i< step;i++) {
System.out.println(MessageFormat.format("{0}线程{1}执行中进行{2}阶段", getNow(), threadName, i+1));
Thread.sleep(runTime /step);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(MessageFormat.format("{0}线程{1}结束", getNow(),threadName));
}
public Integer getRunTime() {
return runTime;
}
public void setRunTime(Integer runTime) {
this.runTime = runTime;
}
}
static String getNow() {
DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.S");
return formatter.format(new Date());
}
}