- 如果线程池工作线程数<corePoolSize,创建新线程执行task,并不断轮训t等待队列处理task。
- 如果线程池工作线程数>=corePoolSize并且等待队列未满,将task插入等待队列。
- 如果线程池工作流程数>=corePoolSize并且等待队列已满,且工作线程数<maximumPoolSize,创建新线程执行task。
- 如果线程池工作流程数>=corePoolSize并且等待队列已满,且工作线程数=maximumPoolSize,执行拒绝策略。
jdk1.8 execute源码
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.
* 如果运行的线程数小于corePoolSize,尝试创建一个新线程(Worker),并执行它的第一个任务command
* 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.
* 如果task成功插入等待队列,我们仍需要进行双重校验是否可以成功添加一个线程
(因为有的线程可能在我们上次检查以后已经死掉了)或者在我们进入这个方法后线程池已经关闭了
* 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();
//判断当前worker线程总数是否小于核心线程数,如果是则创建worker线程添加到核心线程池
if (workerCountOf(c) < corePoolSize) {
//创建并启动workder线程,并且轮训等待队列处理新的task
if (addWorker(command, true))
return;
c = ctl.get();
}
//线程池处于运行状态,并且可以将task插入等待队列中
//第一次校验线程池在运行状态
if (isRunning(c) && workQueue.offer(command)) {
int recheck = ctl.get();
//第二次校验线程池运行状态,防止在第一次校验后线程池关闭。如果关闭,则从等待队列中删除并拒绝task
if (! isRunning(recheck) && remove(command))
reject(command);
//如果线程数为0,新建线程并且不指定firstTask,之后worker会轮训等待队列
else if (workerCountOf(recheck) == 0)
addWorker(null, false);
}
//线程池已关闭或者等待队列已满,这里尝试创建一个worker,如果创建失败,则拒绝该task
else if (!addWorker(command, false))
reject(command);
}
线程池的几种类型:
FixedThreadPool 固定线程池
关键在于使用LinkedBlockingQueue作为阻塞队列,该队列无限大,这会使得线程池可用线程最大数就是核心线程最大数
new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>());
SingleThreadExecutor
跟FixedThreadPool线程池相似,核心线程数为1,阻塞队列中的任务顺序执行,最多只有一个线程处理
new FinalizableDelegatedExecutorService (new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()));
CachedThreadPool
线程池核心线程数指定为0,最大线程数为Integer.MAX_VALUE,阻塞队列为SynchronousQueue(同步队列,有任务马上就提交),线程池中的线程数随着任务的提交创建,线程可复用,空闲线程超过60秒未使用会被销毁
new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>());
WorkStealingPool(偷窃线程池)
创建一个ForkJoinPool,该线程池中每个线程都维护了一个等待队列,线程间在处理过程中会尝试“偷窃”其他线程的等待队列中的任务 并处理, 适合对一个较大的计算做处理,有分治的思想在里面
new ForkJoinPool (Runtime.getRuntime().availableProcessors(),// CPU的核心数 ForkJoinPool.defaultForkJoinWorkerThreadFactory, null, true);