线程池的实现原理
线程池处理流程
(1)线程池判断核心线程池里的线程是否都在执行任务。如果不是,则创建一个新的工作线程来执行任务。如果核心线程池里的线程都在执行任务,则进入下个流程
(2)线程池判断工作队列是否已经满。如果工作队列没有满,则将新提交的任务存储在这个工作队列里。如果工作队列满了。则进入下一个流程
(3)线程池判断线程池的线程是否都处于工作状态。如果没有,则创建一个新的工作线程来执行。如果已经满了,则交给饱和策略来处理这个任务。
线程池主要处理流程
ThreadPoolExecutor执行execute()方法示意图
)
ThreadPoolExecutor执行execute()方法分下面4种情况
(1)如果当前运行的线程少于corePoolSize,则创建新线程来执行任务(执行这一步骤需要获取全局锁)
(2)如果运行的线程等于或多余corePoolSize,则将任务加入到BlockingQueue。
(3)如果无法将任务加入BlockingQueue(队列已满),则创建新的线程来处理任务(执行这一步需要全局锁)
(4)如果创建新线程将使当前运行的线程超出maximumPoolSize,任务将被拒绝,并调用RejectedExecutionHandler.rejectedExecution()方法。
ThreadPoolExecutor采取上述步骤的总体设计思路,是为了在执行execute()方法时,尽可能地避免获取全局锁(那将会是一个严重的可伸缩瓶颈)。在ThreadPoolExecute完成预热之后(当前运行的线程数大于等于corePoolSize),几乎所有的execute()方法调用都是执行步骤2,而步骤2不需要获取全局锁。。
源码分析
public void execute(Runnable command) {
if (command == null)
throw new NullPointerException();
使用原子类获取当前线程数AtomicInteger
int c = ctl.get();
工作线程小于核心线程数(corePoolSize)
if (workerCountOf(c) < corePoolSize) {
将当前线程作为第一个任务启动新线程。
if (addWorker(command, true))
return;
c = ctl.get();
}
如果线程数少于30且能够在(BlockingQueue)阻塞队列中成功排队
if (isRunning(c) && workQueue.offer(command)) {
重新检查工作数量
int recheck = ctl.get();
如果当前队列中的线程数大于30则将当前线程从队列中移除
if (! isRunning(recheck) && remove(command))
拒绝执行当前任务
reject(command);
else if (workerCountOf(recheck) == 0)
addWorker(null, false);
}
如果不能将线程排队,那么添加一个新线程,如果失败,任务已关闭或已饱和
else if (!addWorker(command, false))
拒绝该任务
reject(command);
}
工作线程:线程池创建线程时,会将线程封装成工作线程Worker,Worker在执行完任务后,还会循环获取工作队列里的任务来执行。
循环获取工作队列里的任务
/** Delegates main run loop to outer runWorker */
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);
Throwable thrown = null;
try {
task.run();
} catch (RuntimeException x) {
thrown = x; throw x;
} catch (Error x) {
thrown = x; throw x;
} catch (Throwable x) {
thrown = x; throw new Error(x);
} finally {
afterExecute(task, thrown);
}
} finally {
task = null;
w.completedTasks++;
w.unlock();
}
}
completedAbruptly = false;
} finally {
processWorkerExit(w, completedAbruptly);
}
}
ThreadPoolExecutor中线程执行任务示意图
线程池中的线程执行任务分两种情况
(1)在execute()方法中创建一个线程时,会让这个线程执行当前任务
(2)这个线程执行完上图的任务1后,会反复从BlockingQueue获取任务来执行。