线程池模型
大致的线程池模型如下图所示
- 提交任务,如果线程池中的活跃线程数小于核心线程数,则开启新的线程,直到核心线程数满了为止
- 如果核心线程用完了,则会放到队列中
- 如果队列中放不下了,才会开启新的线程
- 线程会自旋,从队列中拉取新的任务
- 如果线程在自旋的过程中,发现自己拉取超时了,并且线程数大于核心线程数,则跳出自旋,直接结束自己的线程
- 核心线程继续自旋,直至手动结束线程池
初始化线程池
ThreadPoolExecutor pool = new ThreadPoolExecutor(1,//最小线程数|核心线程数
2,//最大线程数
200L,//非核心线程数最大存活时间
TimeUnit.MICROSECONDS,//时间单位
new ArrayBlockingQueue<>(200),//队列
new ThreadPoolExecutor.AbortPolicy());//拒绝策略
点进源码去看,发现构造方法什么事情都没干,只是把传进去的参数赋值给了成员变量
那么看来,核心部分应该是在提交线程的地方了
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;
}
提交线程
提交一个普通线程
pool.execute(new Runnable() {
@Override
public void run() {
System.out.println(123);
}
});
因为线程池的代码太多,就只列举出来重要的部分
execute方法中
int c = ctl.get();
//如果当前线程的数量小于核心线程的数量,则添加核心线程
if (workerCountOf(c) < corePoolSize) {
if (addWorker(command, true))
return;
c = ctl.get();
}
//如果当前线程正在运行,并且入队成功
if (isRunning(c) && workQueue.offer(command)) {
int recheck = ctl.get();
//如果当前线程没有运行,则执行拒绝策略
if (! isRunning(recheck) && remove(command))
reject(command);
//如果工作的线程等于0,则提交一个空的线程到线程池中
else if (workerCountOf(recheck) == 0)
addWorker(null, false);
}
//如果添加任务失败,执行拒绝策略
else if (!addWorker(command, false))
reject(command);
addworker方法
//创建一个worker对象
Worker w = new Worker(firstTask);
//获取worker中的thread,这个thread不是用户添加的,是线程池调用线程工厂创建的
final Thread t = w.thread;
//执行thread的run方法
t.start();
Worker的构造方法
可以看到,用户提交的任务被当成了普通的成员变量了
把自己当成了一个线程,传进newThread中了,所以上边的start方法,其实是执行worker的run方法
Worker(Runnable firstTask) {
setState(-1); // inhibit interrupts until runWorker
this.firstTask = firstTask;
this.thread = getThreadFactory().newThread(this);
}
worker中的run方法
public void run() {
runWorker(this);
}
runWorker方法
可以看到,其实实际执行的是用户提交的线程中的run方法
因为worker、生成的线程、用户提交的线程,全部都是现成,所以会造成思绪乱,被绕进去的感觉
//空方法,用来给用户拓展用的
beforeExecute(wt, task);
Runnable task = w.firstTask;
task.run();
//当task不为空时,就一直循环,当为空时,就跳出循环
while (task != null || (task = getTask()) != null)
//空方法,用来给用户拓展用的
afterExecute(task, thrown);
getTask方法
可以看到,如果设置了线程最大存活时间,则使用线程最大存活时间去拉取,否则,直接阻塞拉取
Runnable r = timed ?
workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
workQueue.take();