您的位置:首页 > 其它

ThreadPoolExecutor一些原理问题

2014-02-28 11:53 423 查看
今天被同事问到,ThreadPoolExecutor是怎么在线程执行后,保存线程的; worker线程去调用具体的业务线程,是不是就启动了两次线程。

平时用的比较多的是用ExecutorService 来创建newCachedThreadPool(), newFixedThreadPool(),
SingleThreadExecutor()等

看了一下源代码,这几个建线程池的方法都是创建ThreadPoolExecutor

public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler)

corePoolSize就是运行的核心线程的数,maximumPoolSize就是最大线程数,keepAliveTime是空闲线程的等待时间,workQueue是用来存放等待线程的。

当poolSize<corePoolSize时,每新来一个任务,则会创建一个工作线程(worker)来处理当前的任务, worker 处理完第一个线程后,会处理queue里的线程。worker在keepAliveTime的时间内,如果没有收到新的任务,则该worker会消失

1. ThreadPoolExecutor是怎么在线程执行后,一直保留worker线程(小于corePoolSize)存活的?
答案在getTask方法的代码里:
Runnable getTask() {
for (;;) {
try {
int state = runState;
if (state > SHUTDOWN)
return null;
Runnable r;
if (state == SHUTDOWN)  // Help drain queue
r = workQueue.poll();
else if (poolSize > corePoolSize || allowCoreThreadTimeOut)
r = workQueue.poll(keepAliveTime, TimeUnit.NANOSECONDS);
else
r = workQueue.take();
if (r != null)
return r;
if (workerCanExit()) {
if (runState >= SHUTDOWN) // Wake up others
interruptIdleWorkers();
return null;
}
// Else retry
} catch (InterruptedException ie) {
// On interruption, re-check runState
}
}
}


当前的线程数<corePoolSize时,workerCanExit()返回false,
无条件循环到 r = workQueue.take();
 take是阻塞方法,因此work的线程会一直等待, 不会退出,等到queue里任务后再执行。

2. worker线程去调用具体的业务线程,是不是就启动了两次线程
注意: worker线程会去调用任务线程里的run方法。而不是start方法。从而避免了多次创建线程

private void runTask(Runnable task) {
final ReentrantLock runLock = this.runLock;
runLock.lock();
try {
/*
* Ensure that unless pool is stopping, this thread
* does not have its interrupt set. This requires a
* double-check of state in case the interrupt was
* cleared concurrently with a shutdownNow -- if so,
* the interrupt is re-enabled.
*/
if (runState < STOP &&
Thread.interrupted() &&
runState >= STOP)
thread.interrupt();
/*
* Track execution state to ensure that afterExecute
* is called only if task completed or threw
* exception. Otherwise, the caught runtime exception
* will have been thrown by afterExecute itself, in
* which case we don't want to call it again.
*/
boolean ran = false;
beforeExecute(thread, task);
try {
task.run();
ran = true;
afterExecute(task, null);
++completedTasks;
} catch (RuntimeException ex) {
if (!ran)
afterExecute(task, ex);
throw ex;
}
} finally {
runLock.unlock();
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息