线程池使用代码:
public static void main(String[] args) {
ExecutorService service = Executors.newFixedThreadPool(3);
for (int i = 0; i < 12; i++) {
service.submit(() -> System.out.println("name " + Thread.currentThread()));
}
}
主要分析线程池的创建过程和submit()执行过程.
Module One: 创建线程的过程
创建线程池对象
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), defaultHandler);
}
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.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.workQueue = workQueue;
this.keepAliveTime = unit.toNanos(keepAliveTime);
this.threadFactory = threadFactory;
this.handler = handler;
}
从设计上考虑的话,Executors 是创建线程池对象的工厂类,工厂类设计模式是一种把对象的创建和使用分离的设计模式,工厂类提供对象的创建方法。
- corePoolSize 核心线程数,线程池中固定存在的线程数量,空闲时也不会终止。
- maximumPoolSize 最大线程数,线程池中允许存在的最大线程的数量,可以是超过 corePoolSize 的数,但是超过的部分,任务执行完后,线程会被终止。
- keepAliveTime 超过 corePoolSize 的线程空闲等待任务的最长时间,超过这个时间线程被终止。
- workQueue 阻塞队列,任务数超过 corePoolSize 时新来的任务会存放在任务队列中
- threadFactory 线程工厂类,用于创建线程
- handler 拒绝策略,当核心线程数和队列都满时,处理之后任务的策略
线程池对象参数
主要针对Executors中的一些默认参数做一个举例
workQueue
- LinkedBlockQueue
- DelayedWorkQueue
- SynchronousQueue
RejectedExecutionHandler
- AbortPolicy (throw RejectedExecutionException)
线程池的执行过程
Step One: 提交任务
public Future<?> submit(Runnable task) {
if (task == null) throw new NullPointerException();
RunnableFuture<Void> ftask = newTaskFor(task, null);
execute(ftask);
return ftask;
}
- 创建一个 RunnableFuture 对象,这个对象是无返回值的
- 执行 RunnableFuture
protected <T> RunnableFuture<T> newTaskFor(Runnable runnable, T value) {
return new FutureTask<T>(runnable, value);
}
问题一,FutureTask是什么
Step Two: 执行任务
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
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)
addWorker(null, false);
}
else if (!addWorker(command, false))
reject(command);
}
- ctl是一个 AtomicInteger 对象,它由两部分组成,分别是 workerCount 和 runState.
- 其中 workerCount 代表的是当前线程池内核心线程数内的已启动的线程数,也就是说,当前线程池内的任务超过 corePoolSize 时,workerCount = corePoolSize.
- runState 有五种状态,后面会再分析
- RUNNING: 接收新任务且读取队列中的任务
- SHUTDOWN: 不再接收新任务,但是会读取任务队列中的任务
- STOP: 停止,不接受新任务且任务队列也不再读取
- TIDYING 暂停所有任务,workerCount = 0, thread 会调用 terminated()
- TERMINATED terminated() 方法执行完成
- 首先会判断 workerCount 是否小于 corePoolSize , 如果是就创建新的线程执行对应的 runnable
- 如果现在是 RUNNING 状态且队列未满,则加入队列。加入队列成功后会有一个二次检测的过程,如果当前线程池状态变化,不再是 RUNNING 则要从队列中移除 runnable, 如果状态没变,但是 workerCount = 0, 则创建一些新线程
- 队列已满的情况下,判断当前线程数是否小于 maximumPoolSize, 如果小于则创建线程执行任务,否则失败执行拒绝策略。
private boolean addWorker(Runnable firstTask, boolean core) {
...
boolean workerStarted = false;
boolean workerAdded = false;
Worker w = null;
try {
w = new Worker(firstTask);
final Thread t = w.thread;
if (t != null) {
final ReentrantLock mainLock = this.mainLock;
mainLock.lock();
try {
int c = ctl.get();
if (isRunning(c) ||
(runStateLessThan(c, STOP) && firstTask == null)) {
if (t.getState() != Thread.State.NEW)
throw new IllegalThreadStateException();
workers.add(w);
workerAdded = true;
int s = workers.size();
if (s > largestPoolSize)
largestPoolSize = s;
}
} finally {
mainLock.unlock();
}
if (workerAdded) {
t.start();
workerStarted = true;
}
}
} finally {
if (! workerStarted)
addWorkerFailed(w);
}
return workerStarted;
}
- 省略了一部分代码,主要是对当前线程池的状态做判断
- 如果当前线程池状态不是 RUNNING 则拒绝接受新的任务
- 根据core判断是核心线程还是最大线程,超过则返回fasle
- 创建一个 Worker 对象,加锁,放到 workers 的 Set 集合中。添加成功调用 thread.start()
Step Three: Worder 对象
Worker 是一个任务执行的类,创建时会有一个FirstTask且会创建一个新的线程,线程执行完FirstTask后会循环从BlockingQueue中取任务执行。
Worker(Runnable firstTask) {
setState(-1); // inhibit interrupts until runWorker
this.firstTask = firstTask;
this.thread = getThreadFactory().newThread(this);
}
public void run() {
runWorker(this);
}
final void runWorker(Worker w) {
Thread wt = Thread.currentThread();
Runnable task = w.firstTask;
w.firstTask = null;
w.unlock(); // allow interrupts
boolean completedAbruptly = true;
try {
while (task != null || (task = getTask()) != null) {
w.lock();
// If pool is stopping, ensure thread is interrupted;
// if not, ensure thread is not interrupted. This
// requires a recheck in second case to deal with
// shutdownNow race while clearing interrupt
if ((runStateAtLeast(ctl.get(), STOP) ||
(Thread.interrupted() &&
runStateAtLeast(ctl.get(), STOP))) &&
!wt.isInterrupted())
wt.interrupt();
try {
beforeExecute(wt, task);
try {
task.run();
afterExecute(task, null);
} catch (Throwable ex) {
afterExecute(task, ex);
throw ex;
}
} finally {
task = null;
w.completedTasks++;
w.unlock();
}
}
completedAbruptly = false;
} finally {
processWorkerExit(w, completedAbruptly);
}
}
主要逻辑就是当前Worker有一个Thread, 这个Thread 会执行FirstTask 和 getTask() 中取到的任务。
private Runnable getTask() {
boolean timedOut = false; // Did the last poll() time out?
for (;;) {
...
try {
Runnable r = timed ?
workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS) :
workQueue.take();
if (r != null)
return r;
timedOut = true;
} catch (InterruptedException retry) {
timedOut = false;
}
}
}
getTask() 中循环从 workQueue 中取任务,这个workQueue就是线程池构造函数中的 blockingQueue. 如果workQueue是 LinkedBlockQueue 那么响应的当队列里面没有内容的时候,workQueue.take() 会阻塞当前线程。