- 如果当前线程数量小于corePoolSize,新任务会创建一个新的线程去执行;
- 如果当前线程数量大于corePoolSize,小于maximumPoolSize,新任务会加入队列当中,即便存在空闲的线程;
线程池状态
线程池包括以下几种状态:
- RUNNING:接收新任务并且可以处理队列中的任务;
- SHUTDOW:不接受新任务,但是可以处理队列中的任务;
- STOP:不接受新任务、不处理队列中的任务并且中断处理中的任务;
- TIDYING:所有任务已经终止,线程数量为0,所有线程将执行terminated()方法;
- TERMINATED:terminated()方法已经执行完成。
问题
- 提交任务包括execute和submit两种方法,这两个有什么区别?
两个方法都可以提交任务,submit可以获取到任务执行的结果,execute方法无返回值。
- 线程池shutDown和shutDownNow两个方法的区别
这两个方法都可以终止线程池,不再接受新的任务。但是shutDown会等所有正在执行和任务队列中的任务执行完成,但是shutDownNow立刻终止线程池,线程池任务队列中的任务不会被执行,正在被执行的任务会被立刻终止,抛出线程被中断的异常:java.lang.InterruptedException: sleep interrupted。
线程池任务执行流程
- 为什么设置核心线程数和最大线程数
- 当任务队列满了之后,才会创建新的线程;
- 业务有高峰和低谷,在业务低谷期,没必要维护这么多的线程数,线程的切换也会耗费CPU资源。
队列都是有序的吗?
- 队列包括LinkedBlockingQueue、ArrayBlockingQueue、PriorityBlockingQueue、LinkedTransferQueue等,像链表和数组队列都是有序的,优先级队列会按照任务的优先级入队,是无序的。
线程池为什么使用阻塞队列?
使用阻塞队列可以减少对CPU资源的消耗。当线程等待新的任务时,如果是非阻塞队列,会一直遍历队列,直到队列中有新的任务。而非阻塞队列会放弃CPU资源,直到有新的任务到来。
try {
Runnable r = timed ?
workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
workQueue.take();
if (r != null)
return r;
timedOut = true;
} catch (InterruptedException retry) {
timedOut = false;
}
�
任务提交源码分析
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.
*/
int c = ctl.get();
//1.判断当前活跃线程数是否大于corePoolSize,如果小于corePoolSize,新增一个线程,否则尝试放入队列
if (workerCountOf(c) < corePoolSize) {
if (addWorker(command, true))
return;
c = ctl.get();
}
//2.1.如果线程池是RUNNING状态,那么将任务放入队列。此时有个二次确认,判断线程池状态,防止在这个过程中线程池已经STOP,无法执行
//入队的任务;
//2.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))
reject(command);
}