时隔上一篇技术文章更新差不多有3个星期了,起因的话在上一篇文章中写啦。废话不多说,开始咱们的线程池源码的第二轮浏览。
回顾
简略回顾下上一篇线程池源码中波及的两个办法,一个是execute()
执行工作的入口,还有一个是addWorker()
最艰深地了解就是是否须要增加新线程。而在addWoker()
的开端有这样一段代码
if (workerAdded) { t.start(); workerStarted = true;}
显著地看到这里通过start()
办法开启了多线程,而如果想要看线程的执行逻辑,就须要去到对应类中查看run办法,这里的t就是Worker
类外面的一个成员变量,所以重点要看Worker
类中的run()
办法。
runWorker()
run()
办法的源码如图所示,最初是到了runWorker()
间接来看runWorker的源码
- 开始是一个循环,要么执行worker自带的第一个工作(firstTask),要么通过
getTask()
获取工作 有工作首先得保障线程池是失常的,以下两种状况均调用
wt.interrupt()
给线程设置中断标记位- 线程池处于STOP状态,也就是不承受新工作,也不执行队列中的工作
- 如果线程的标记位曾经为true,那么分明标记位,此时的线程池状态为STOP状态,这里看起来可能比拟顺当,有了第一种状况为什么还要第二种,不了解的能够先略过,前面会讲的。
- 失常状况下是调用
beforeExecute()
和afterExecute()
包裹者task.run()
看一下是如何自定义前置和后置执行逻辑
因为是换电脑写了,所以例子可能和前一篇文章的不齐全一样,然而表白的是同一个意思
public class ThreadPoolExamples { public static void main(String[] args) { ThreadPoolExecutor executor = new MyThreadPoolExecutor(5, 5, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>()); MyThread myThread = new MyThread(); executor.execute(myThread); }}class MyThread extends Thread { @Override public void run() { System.out.println(Thread.currentThread().getName() + " is running"); }}class MyThreadPoolExecutor extends ThreadPoolExecutor { @Override protected void beforeExecute(Thread t, Runnable r) { System.out.println("【" + Thread.currentThread().getName() + " custom before execute】"); } @Override protected void afterExecute(Runnable r, Throwable t) { System.out.println("【" + Thread.currentThread().getName() + " is done】"); } MyThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) { super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue); }}
首先就是要创立本人的MyThreadPoolExecutor
类,继承ThreadPoolExecutor
,而后重写beforeExecute()
和afterExecute()
定义本人的逻辑即可,看下测试后果
能够看到前置和后置都曾经依照既定的逻辑在运行了,乏味的是,22分钟过来了(不要问我为什么这么久,拿外卖吃货色去了)线程池还是没有停,为什么会这样呢。
留神后面剖析runWorker()
第一步的时候是一个循环,而后通过firstTask 或者getTask()
获取工作,如果两种形式都获取不到工作,线程池就应该退出,看来神秘在getTask()
中。
getTask()
次要目标顾名思义就是获取到须要执行的工作,间接看源码
一进来也是一个死循环,能够先聚焦什么时候会退出循环,必定是不失常的状况下会退出
- 当线程池状态不处于RUNNING或者SHUTDOWN的时候,或者是当线程处于SHUTDOWN然而工作队列中没有工作
- 当wc大于最大线程数并且工作队列为空的时候,或者当wc大于外围线程数并且timedOut为true并且外围队列为空的时候,或者如果设置了allowCoreThreadTimeOut,并且wc > 1或者外围队列为空的时候
- 除了不失常的状况,接下来就是从工作队列中获取工作,不过是依据timed的来决定是用
poll()
还是take()
。 - 如果能取出工作,就间接返回工作;如果没有工作,要么超时设置timedOut为ture,要么是抛出异样重置timedOut为false。
能够看到,只有上述不失常的状况下退出循环,工作返回null,进而导致runWorker()
中的while循环退出,最初整个线程池敞开。否则都是会始终在getTask()
这里死循环。
到这里,为什么说线程池可能节俭资源呢,是因为其实它创立的线程的耗费只是体现在了Worker类的创立中,把其它要实现的工作放在工作队列外面,而后getTask()
获取工作,最初执行工作(调用task.run()
)
回绝策略
这个是在最开始execute()
的时候调用的
具体是如何请看上面的动图
能够看到,最初是调用了RejectedExecutionHandler
接口中的rejectedExecution(Runnable r, ThreadPoolExecutor executor);
办法,而后默认是有4种实现形式
有凋谢的接口,那必定是能自定义实现类的
class MyRejectedExecutionHandler implements RejectedExecutionHandler { @Override public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) { System.out.println("task is rejected"); }}
该说的办法也根本都说了,用到的工作队列(BlockingQueue)在前面会另说,下一篇文章就总结下jdk的线程池啦!
创作不易,如果对你有帮忙,欢送点赞,珍藏和分享啦!
上面是集体公众号,有趣味的能够关注一下,说不定就是你的宝藏公众号哦,根本2,3天1更技术文章!!!