线程池构造参数
corePoolSize
核心线程池大小:如果任务进来,当前Worker数量小于corePoolSize则直接启动一个新的Worker进行作业
maximumPoolSize
第一次看到这个参数配置时错误的理解为:如果Worker数=corePoolSize,此时又有新任务提交到线程池,并且当前Worker数<maximumPoolSize,则立马启动新的Worker进行作业。
too young too simple,这个理解是错误的。。。
最大线程池大小:新任务提交至线程池,当前Worker数量超过corePoolSize大小,则会放入队列,如果队列也已经满了,此时再去判断当前Worker数量是否超过maximumPoolSize大小,如果否则创建新Worker进行作业
keepAliveTime
与参数TimeUnit共用,当线程池空闲时,对于空闲的Worker保持活跃的时间。例如:10秒,Worker数超过corePoolSize时,如果空闲时间超过10秒则会回收Worker至corePoolSize大小
workQueue
工作队列,当Worker数
threadFactory
线程工厂
RejectedExecutionHandler
线程池跑满时对线程的拒绝处理接口
验证maximumPoolSize代码
线程池代码
package com.gallant.test;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* threadpool
*
* @author : 会灰翔的灰机
* @date : 2021/1/17
*/
public class ThreadPool {
public static void main(String[] args) {
int corePoolSize = 3;
int maximumPoolSize = 10;
long keepAliveTime = 10;
TimeUnit unit = TimeUnit.SECONDS;
BlockingQueue<Runnable> workQueue = new LinkedBlockingQueue<>(5);
RejectedExecutionHandler handler = (r, executor) -> System.out.println(r + " task is rejected");
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, (r)-> new MyTask(), handler);
for (int i = 0; i < 100; i++) {
threadPoolExecutor.submit(() -> {});
System.out.println(i+1 + ", queue size:"+threadPoolExecutor.getQueue().size());
}
}
}
任务代码
package com.gallant.test;
import java.util.concurrent.atomic.AtomicInteger;
/**
* task
*
* @author : 会灰翔的灰机
* @date : 2021/1/17
*/
public class MyTask extends Thread {
private static final AtomicInteger CNT = new AtomicInteger();
public MyTask() {
super(null, null, "MyTask-" + CNT.getAndAdd(1));
}
@Override
public void run() {
super.run();
System.out.println(this.getName() + " is running");
try {
Thread.sleep(1000000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
执行结果
1, queue size:0
MyTask-0 is running
2, queue size:0
MyTask-1 is running
3, queue size:0
MyTask-2 is running
4, queue size:1
5, queue size:2
6, queue size:3
7, queue size:4
8, queue size:5
9, queue size:5
MyTask-3 is running
10, queue size:5
MyTask-4 is running
11, queue size:5
MyTask-5 is running
12, queue size:5
MyTask-6 is running
13, queue size:5
MyTask-7 is running
14, queue size:5
MyTask-8 is running
15, queue size:5
MyTask-9 is running
java.util.concurrent.FutureTask@7cc355be task is rejected
16, queue size:5
java.util.concurrent.FutureTask@6e8cf4c6 task is rejected
17, queue size:5
结论
3个核心Worker执行任务时,继续有任务进来时,放入队列,当队列满时(队列大小=5),才会继续增加新的Worker工作,直至Worker数量到达最大值时,如果仍然有任务进来,则执行拒绝处理接口来决策如何处理溢出的任务
验证keepAliveTime
线程池代码
package com.gallant.test;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* threadpool
*
* @author : 会灰翔的灰机
* @date : 2021/1/17
*/
public class ThreadPool2 {
public static void main(String[] args) {
int corePoolSize = 3;
int maximumPoolSize = 10;
long keepAliveTime = 10;
TimeUnit unit = TimeUnit.SECONDS;
BlockingQueue<Runnable> workQueue = new LinkedBlockingQueue<>(5);
RejectedExecutionHandler handler = (r, executor) -> System.out.println(r + " task is rejected");
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, (r)-> new MyTask(), handler);
for (int i = 0; i < 15; i++) {
threadPoolExecutor.submit(() -> {});
}
for (int i = 0; i < 100000; i++) {
System.out.println(i + 1 + " seconds, active count:" + threadPoolExecutor.getActiveCount()
+ " , completedTaskCount: " + threadPoolExecutor.getCompletedTaskCount() + ", poolSize:"
+ threadPoolExecutor.getPoolSize());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
任务代码
package com.gallant.test;
import java.util.concurrent.atomic.AtomicInteger;
/**
* task
*
* @author : 会灰翔的灰机
* @date : 2021/1/17
*/
public class MyTask2 extends Thread {
private static final AtomicInteger CNT = new AtomicInteger();
public MyTask2() {
super(null, null, "MyTask2-" + CNT.getAndAdd(1));
}
@Override
public void run() {
super.run();
System.out.println(this.getName() + " is running");
}
}
执行结果
MyTask2-0 is running
MyTask2-1 is running
MyTask2-2 is running
MyTask2-3 is running
MyTask2-4 is running
MyTask2-5 is running
MyTask2-6 is running
MyTask2-7 is running
MyTask2-8 is running
MyTask2-9 is running
1 seconds, active count:10 , completedTaskCount: 0, poolSize:10
2 seconds, active count:10 , completedTaskCount: 0, poolSize:10
与预期效果不同,为什么完成任务数量始终为0?明明我们的任务是立即就可以执行完成的
问题分析
线程池原理不多说,简而言之就是将任务封装为Worker进行执行,看下Worker的构造器
Worker(Runnable firstTask) {
setState(-1); // inhibit interrupts until runWorker
this.firstTask = firstTask;
this.thread = getThreadFactory().newThread(this);
}
问题很明显了,由于我们重写了自定义的线程工厂接口的实现,使得线程池没有按照其原有的Worker模式执行,此时不会再执行Worker线程,因为我们的自定义工厂里面忽略target线程,也就是忽略了this(Worker),既然走不到Worker里面,也就不会出现在Worker执行完成时,将Worker从workers中移除,也就如我们所见,完成任务数始终为0,因为始终走不到下面的代码中。也就是说只添加了Worker,但是没有去执行Worker
final void runWorker(Worker w) {
Thread wt = Thread.currentThread();
Runnable task = w.firstTask;
w.firstTask = null;
w.unlock(); // allow interrupts
boolean completedAbruptly = true;
try {
while (task != null || (task = getTask()) != null) {
...
} finally {
processWorkerExit(w, completedAbruptly);
}
}
问题修复
修复后的代码如下:
package com.gallant.test;
import java.util.concurrent.atomic.AtomicInteger;
/**
* task
*
* @author : 会灰翔的灰机
* @date : 2021/1/17
*/
public class MyTask3 extends Thread {
private static final AtomicInteger CNT = new AtomicInteger();
public MyTask3(Runnable target) {
super(null, target, "MyTask2-" + CNT.getAndAdd(1));
}
@Override
public void run() {
System.out.println(this.getName() + " is running");
super.run();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
package com.gallant.test;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.RejectedExecutionHandler;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* threadpool
*
* @author : 会灰翔的灰机
* @date : 2021/1/17
*/
public class ThreadPool3 {
public static void main(String[] args) {
int corePoolSize = 3;
int maximumPoolSize = 10;
long keepAliveTime = 10;
TimeUnit unit = TimeUnit.SECONDS;
BlockingQueue<Runnable> workQueue = new LinkedBlockingQueue<>(5);
RejectedExecutionHandler handler = (r, executor) -> System.out.println(r + " task is rejected");
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(corePoolSize, maximumPoolSize,
keepAliveTime, unit, workQueue, MyTask3::new, handler);
new Thread(() -> {
for (int i = 0; i < 100000; i++) {
System.out.println(i + 1 + " seconds, active count:" + threadPoolExecutor.getActiveCount()
+ " , completedTaskCount: " + threadPoolExecutor.getCompletedTaskCount() + ", poolSize:"
+ threadPoolExecutor.getPoolSize());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}).start();
for (int i = 0; i < 15; i++) {
threadPoolExecutor.submit(() -> {});
}
}
}
修复后执行结果
1 seconds, active count:0 , completedTaskCount: 0, poolSize:0
MyTask2-0 is running
MyTask2-1 is running
MyTask2-2 is running
MyTask2-3 is running
MyTask2-4 is running
2 seconds, active count:0 , completedTaskCount: 15, poolSize:5
3 seconds, active count:0 , completedTaskCount: 15, poolSize:5
4 seconds, active count:0 , completedTaskCount: 15, poolSize:5
5 seconds, active count:0 , completedTaskCount: 15, poolSize:5
6 seconds, active count:0 , completedTaskCount: 15, poolSize:5
7 seconds, active count:0 , completedTaskCount: 15, poolSize:5
8 seconds, active count:0 , completedTaskCount: 15, poolSize:5
9 seconds, active count:0 , completedTaskCount: 15, poolSize:5
10 seconds, active count:0 , completedTaskCount: 15, poolSize:5
11 seconds, active count:0 , completedTaskCount: 15, poolSize:3
12 seconds, active count:0 , completedTaskCount: 15, poolSize:3
结论
与我们期望相符,共计15个任务,有5个Worker便完成了所有任务,当所有Worker空闲时间大于配置的保持活跃时间(keepAliveTime,案例使用的配置为:10秒)时,则退出超出核心Worker数(corePoolSize)的空闲Worker,保持活跃的Worker数不低于核心Worker数配置(案例使用的配置为3)