上一篇文章讲了有关线程池的一些简单的用法,这篇文章主要是从源码的角度进一步带你们了解线程池的工做流程和工做原理。java
首先先来回顾下如何使用线程池开启线程多线程
private static void createThreadByThreadPoolExecutor() { ThreadPoolExecutor executor = new ThreadPoolExecutor(5,5, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>()); for (int i = 0; i < 10; i++) { MyThread myThread = new MyThread(); executor.execute(myThread); }
能够看到其实没有其它特殊的地方,除了构建线程池的代码,其它最终要的就是executor.execute(myThread)
行代码了。函数
在多线程系列的第一篇文章中提到了线程和进程的状态,线程池一样也有状态,以下:spa
terminated()
函数terminated()
函数调用完后就进入了此状态首先须要知道4个概念,Worker
、workers
、workQueue
和 task
.线程
在线程池中有个比较重要的类,那就是Worker
,能够看到其实现了Runnable
接口(其实就是工做线程),继承了AbstractQueuedSynchronizer
类(俗称AQS
,在多线程中是很重要的类)code
workers
就是Worker
的一个集合,private final HashSet<Worker> workers = new HashSet<Worker>();
task
:须要执行的任务,也就是execute()
中的参数,实现了Runnable
接口workQueue
就是工做队列,就是上一篇文章中线程池构造函数中的工做队列,里面存储的就是须要执行的任务,队列是实现BlockingQueue
接口的类,有如下这些实现对象
execute()
本方法传进去的类是须要实现Runnable接口的,做为一个command
传进去继承
遇到新的任务后接口
若是线程池是正常的工做状态,而且工做队列可以添加任务,此时须要第二轮判断队列
注意:核心线程和非核心线程只是语义上的说法, 没有本质上的区别
addworker()
addworker
的做用是检查是否能够根据当前池状态和给定界限(核心或最大值)添加新线程 ,而且经过第二个参数来断定是否建立核心线程,当为true的时候就是核心线程,反之就是非核心线程。源码里的注释以下
来看看代码具体是如何的
一进来就是一个死循环,这个死循环最主要的目的是确认线程池状态是否正常。若是线程池的状态大于SHUTDOWN,也就是处于STOP、TIDYING或者TERMINATED的时候,线程池都没了,还建立worker干啥,直接返回fasle;当线程池处于SHUTDOWN的时候,又得再次判断:
先来看正常的逻辑,拿到锁,而且开始又一次的获取线程池的状态
alive
那么而说明线程已经开启,直接抛出异常。t.start()
addWorkerFailed()
逻辑。整个的逻辑是比较简单的,就再也不花费篇幅去阐述。到这里,整个addWorker()
的流程是比较清晰的,值得一提的就是第2行代码中的retry
这个看起来是关键字,但其实不是,仅仅只是一个相似标志位的东西,能够是retry,也能够是abc。
一般是配合for循环来使用,搭配continue和break能够达到goto的效果。好比continue retry;
就是跳到一开始最外层的for循环,break retry;
至关于退出整个循环。写一个最简单的例子你们都能知道了。
public class RetryExample { public static void main(String[] args) { abc: for (int i = 0; i < 10; i++) { for (int j = 0; j < 10; j++) { if (j == 2) { continue abc; } if (i == 8) { break abc; } System.out.println("i: " + i + ", j: " + j); } } } }
输出结果以下图所示
创做不易,若是对你有帮助,欢迎点赞,收藏和分享啦!
下面是我的公众号,有兴趣的能够关注一下,说不定就是你的宝藏公众号哦,基本2,3天1更技术文章!!!