9 线程池实现原理
9.1 线程池组成部分
线程池管理器
工作线程
任务队列
任务
9.2 Executor家族
Executor:它是一个顶层接口,其他接口以及类都i继承或实现于它,包含以下方法:
void execute(Runnable command);
ExecutorService:它继承于Executor,是Executor的子接口,在接口内部增加了一些新的方法,例如第6小节讲到的几个方法
Executors:这个类是一个工具类,里面包含一些创建线程池的方法
9.3 线程池实现任务复用的原理
利用相同线程执行不同任务
源码分析
<code>public void execute(Runnablecommand
) { // 判断任务是否为空,为空就抛出异常if
(command
== null) throw new NullPointerException(); int c = ctl.get(); // 如果当前线程数小于核心线程数,就增加Workerif
(workerCountOf(c) < corePoolSize) { //command
就是任务,点击addWorker方法 // 第二个参数用于判断当前线程数是否小于核心线程数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
);}/<code>
因为要查看的是Worker所以进入到addWorker()方法后点击Worker类查看runWorker()方法
<code>w
=
new
Worker(firstTask);private
final
class
Worker
extends
AbstractQueuedSynchronizer
implements
Runnablefinal
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
((runStateAtLeast(ctl.get(),
STOP)
||
(Thread.interrupted()
&&
runStateAtLeast(ctl.get(),
STOP)))
&&
!wt
.isInterrupted())
wt.interrupt();
try
{
beforeExecute(wt,
task);
Throwable
thrown
=
null
;
try
{
//
task是一个Runnable类型,调用run()方法就是运行线程
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);
}}
/<code>
总结:核心原理就是获取到task,如果task不为空就调用run()方法,这样就实现了线程的复用,达到让相同的线程执行不同任务的目的。
10 线程池状态
RUNNING:接受新任务并处理排队任务
SHUTDOWN:不接受新的任务但是处理排队任务
STOP:不接受新的任务,也不处理排队的任务,并中断正在执行的任务,就是调用shutdownNow()带来的效果
TIDYING:中文意思是整洁,意思就是说任务都已经终止,workerCount为零时,线程会转换到TIDYING状态,并将运行terminate()钩子方法
TERMINATED:terminate()运行完成
11 使用线程池的注意点
避免任务的堆积(堆积容易产生内存溢出)
避免线程数过多增加(缓存线程池会导致线程数过度增加)
排查线程泄漏(线程已经执行完毕却无法被回收)