上一篇文章讲了有关线程池的一些简单的用法,这篇文章主要是从源码的角度进一步带大家了解线程池的工作流程和工作原理。
首先先来回顾下「如何使用线程池开启线程」
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)
行代码了。
在多线程系列的第一篇文章中提到了线程和进程的状态,「线程池同样也有状态」,如下:
terminated()
函数terminated()
函数调用完后就进入了此状态首先需要知道「4个概念」,Worker
、workers
、workQueue
和 task
.
Worker
,可以看到其实现了Runnable
接口(其实就是「工作线程」),继承了AbstractQueuedSynchronizer
类(俗称AQS
,在多线程中是很重要的类)
workers
就是Worker
的一个集合,private final HashSet<Worker> workers = new HashSet<Worker>();
task
:需要「执行的任务」,也就是execute()
中的参数,实现了Runnable
接口workQueue
就是「工作队列」,就是上一篇文章中线程池构造函数中的工作队列,里面存储的就是需要执行的任务,队列是实现BlockingQueue
接口的类,有以下这些实现
execute()
本方法传进去的类是需要实现Runnable接口的,作为一个command
传进去
遇到「新的任务」后
❝注意:核心线程和非核心线程只是语义上的说法,「没有本质上的区别」 ❞
addworker()
addworker
的作用是检查是否可以根据当前池状态和给定界限(核心或最大值)「添加新线程」 ,并且「通过第二个参数来判定是否创建核心线程」,当为true的时候就是核心线程,反之就是非核心线程。源码里的注释如下
来看看代码具体是如何的
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);
}
}
}
}
输出结果如下图所示
「创作不易,如果对你有帮助,欢迎点赞,收藏和分享啦!」