1、核心线程数、最大线程数
添加任务时,判断线程数量,来决定加入队列还是直接执行,或者拒绝
如果线程池关闭,那么添加新的任务时, addWorker 中会直接返回 false,就会进入拒绝策略
public void execute(Runnable command) {
int c = ctl.get();
//1、线程数量小于核心数量,添加新的线程
if (workerCountOf(c) < corePoolSize) {
if (addWorker(command, true))
return;
c = ctl.get();
}
//2、线程数量大于核心数量,添加到队列
if (isRunning(c) && workQueue.offer(command)) {
int recheck = ctl.get();
if (! isRunning(recheck) && remove(command))
reject(command);
else if (workerCountOf(recheck) == 0)
addWorker(null, false);
}
//3、线程数量大于核心数量,添加到队列,队列已满,继续添加新的线程
else if (!addWorker(command, false))
//4、超过最大线程,采取拒绝策略
reject(command);
}
2、创建新的线程
创建新的 Thread,在线程池关闭的情况下,就不创建了,除非出现以下的特殊情况
//一般情况:
//处于 SHUTDOWN 状态以上,直接不再创建新的线程;
//处于 SHUTDOWN 状态,传入的任务不为 null,直接不再创建新的线程;
//特殊情况:
//处于 SHUTDOWN 状态,传入的任务为 null,是由于在成功加入队列之后,发现此时的线程数量为0,需要再创建一个新的线程去完成这个任务
if (rs >= SHUTDOWN && ! (rs == SHUTDOWN && firstTask == null && !workQueue.isEmpty()))
return false;
//...省略
Worker w = new Worker(firstTask);
mainLock.lock();
//和上面分析的情况一致,属于特殊情况
if (rs < SHUTDOWN || (rs == SHUTDOWN && firstTask == null)) {
workers.add(w);
}
mainLock.unlock();
//...省略
3、执行任务
首次创建线程的时候,会直接执行任务;其余情况会阻塞的从队列中获取任务
如果线程池关闭了,那么直接使用中断关闭退出
//1、获取任务
while (task != null || (task = getTask()) != null) {
//2、如果线程池处于 SHUTDOWN 状态以上,并且还未中断,直接中断线程
if ((runStateAtLeast(ctl.get(), STOP) || (Thread.interrupted() && runStateAtLeast(ctl.get(), STOP))) &&
!wt.isInterrupted()){
wt.interrupt();
}
//3、执行任务
}
4、获取任务
在获取任务时,如果设置了存活时间,那么超过指定的时间没有获取到任务的线程会自动关闭退出
//1、线程池关闭了,如果处于 SHUTDOWN 而且队列为空
if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
//2、减少线程数量
decrementWorkerCount();
//3、当前线程自动关闭退出
return null;
}
//4、线程数量大于核心线程,默认启用了存活时间
boolean timed = allowCoreThreadTimeOut || wc > corePoolSize;
//5、线程数量大于核心线程、时间到了,关闭当前线程
if ((wc > maximumPoolSize || (timed && timedOut)) && (wc > 1 || workQueue.isEmpty())) {
if (compareAndDecrementWorkerCount(c))
return null;
continue;
}
//6、阻塞获取任务
Runnable r = timed ? workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) : workQueue.take();
if (r != null)
return r;
timedOut = true;
5、Executors
1、newFixedThreadPool
创建固定线程数量的线程池,超出的任务,全部加入到队列中,最多存放 int 的最大值
return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
2、newSingleThreadExecutor
静态线程池,使用包装类,屏蔽了一些方法,实现了真正的单线程串行执行任务
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()));
3、newCachedThreadPool
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
6、示例测试 -- keepalive
package com.sample.modules.test;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
public class ThreadTest {
static class Task implements Runnable{
private int taskId;
private String taskName;
public Task(int taskId, String taskName) {
this.taskId = taskId;
this.taskName = taskName;
}
public int getTaskId() {
return taskId;
}
public void setTaskId(int taskId) {
this.taskId = taskId;
}
public String getTaskName() {
return taskName;
}
public void setTaskName(String taskName) {
this.taskName = taskName;
}
@Override
public void run() {
try {
System.out.println("taskId = "+this.taskId+" taskName = "+this.taskName);
TimeUnit.SECONDS.sleep(3);
}catch (Exception e){
e.printStackTrace();
}
}
}
public static void main(String[] args) throws Exception{
//1、设置队列为0,这样就强制开启到了最大线程数量
BlockingQueue queue = new ArrayBlockingQueue(1);
//2、核心线程为1,最大线程为2,超时时间为3s
ThreadPoolExecutor executor = new ThreadPoolExecutor(1, 2, 3, TimeUnit.SECONDS, queue);
Task task1 = new Task(1, "任务1");
Task task2 = new Task(2, "任务2");
Task task3 = new Task(3, "任务3");
//3、单独开启线程记录状态变化
new Thread(()->{
while (true){
try {
System.out.println("线程总数:"+executor.getPoolSize()+" 活跃总数:"+executor.getActiveCount()+" 队列数量:"+executor.getQueue().size());
TimeUnit.SECONDS.sleep(1);
}catch (Exception e){
e.printStackTrace();
}
}
}).start();
//4、添加3个任务
executor.submit(task1);
executor.submit(task2);
executor.submit(task3);
}
}
打印结果:
线程总数:0 活跃总数:0 队列数量:0
//1.线程数量到达最大值, 两个线程都在执行任务, 队列中有一个任务
线程总数:2 活跃总数:2 队列数量:1
线程总数:2 活跃总数:2 队列数量:1
线程总数:2 活跃总数:2 队列数量:1
//2.两个线程当前任务执行完毕, 其中一个线程获取到队列任务, 另一个阻塞等待
//2.此时线程总数依旧为2, 但是活跃的只剩下一个
线程总数:2 活跃总数:1 队列数量:0
线程总数:2 活跃总数:1 队列数量:0
线程总数:2 活跃总数:1 队列数量:0
//3.没有获取到任务的线程, 阻塞 3s 之后, 还没有获取到任务, 关闭退出
//3.此时线程总数为1, 另一个线程也执行完了数据, 所以活跃总数变为0
线程总数:1 活跃总数:0 队列数量:0
线程总数:1 活跃总数:0 队列数量:0
线程总数:1 活跃总数:0 队列数量:0