图片参考链接:p1
图片参考链接:p2
图片参考链接:p3
一个新的任务提交到线程池时:
1.线程池判断核心线程池里的核心线程是否都在执行任务。 如果不是,让空闲的核心线程来执行任务。如果核心线程池里的线程都在执行任务,则进入下个流程。
2.线程池判断阻塞队列是否已满。 如果阻塞队列没有满,则将新提交的任务存储在阻塞队列中。如果阻塞队列已满,则进入下个流程。
3.线程池判断线程池里的线程数量是否小于最大线程数量(看线程池是否满了)。 如果小于,则创建一个新的工作线程(非核心线程,并给它设置超时时间,当我们处理完这些任务,无需手动销毁这个非核心线程,超时自动销毁)来执行任务。如果已满,则交给拒绝策略来处理这个任务。
之前学习线程池的工作流程的时候,
自己思考了一个问题,
新加入的任务和阻塞队列的任务抢占线程是公平的还是非公平的?
后来看线程池源码发现在核心线程还没满的时候,是非公平的,
核心线程满了是公平的,个人拙见,有误的话还望大佬指正。
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();//空指针异常
/*
* Proceed in 3 steps:
*
* 1. If fewer than corePoolSize threads are running, try to
* start a new thread with the given command as its first
* task. The call to addWorker atomically checks runState and
* workerCount, and so prevents false alarms that would add
* threads when it shouldn't, by returning false.
*
* 2. If a task can be successfully queued, then we still need
* to double-check whether we should have added a thread
* (because existing ones died since last checking) or that
* the pool shut down since entry into this method. So we
* recheck state and if necessary roll back the enqueuing if
* stopped, or start a new thread if there are none.
*
* 3. If we cannot queue task, then we try to add a new
* thread. If it fails, we know we are shut down or saturated
* and so reject the task.
*/
/*
1. 如果正在运行的线程少于corePoolSize(核心线程数),尝试以给定命令作为第一个线程启动新线程任务。
对addWorker的调用以原子方式检查运行状态和workerCount,从而防止可能增加在不应该的情况下,
通过返回false执行线程。
2.如果任务可以成功排队,然后我们仍然需要再次检查是否应该添加线程
(因为自上次检查以来,已有的已死亡)或自进入此方法后池已关闭。
所以我们要重新检查状态,如有必要,在停止排队时回滚排队,
或者在没有排队时启动一个新线程。
3.如果我们无法将任务排队,那么我们将尝试添加一个新任务线程(非核心线程)。
如果失败了,我们知道我们已经被关闭或饱和了,所以拒绝这个任务(执行拒绝策略)。
*/
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);//执行拒绝策略
else if (workerCountOf(recheck) == 0)//工作线程为0的话(池已关闭)
addWorker(null, false);
}
else if (!addWorker(command, false))//如果无法添加工作线程
reject(command);//执行拒绝策略
}