关于JDK源码相关的文章这已经是第四篇了,原创不易,粉丝从几十人到昨天的666
人,真的很感谢之前帮我转发文章的一些朋友们。
从16年开始写技术文章,到现在博客园已经发表了222
篇文章,大多数都是原创,共有800多粉丝,基本上每个月都会有文章的产出。
回顾这几年以来写作的心路历程,一直都是偷偷的写,偷偷的发,害怕被人知道,怕被人骂文章写的太水(之前心理太脆弱了,哈哈)。后面和cxuan聊过后,他建议我给他投稿试试,于是就有了那一篇的万字的AQS
文章。
最近也有好多读者加到我的微信,问一些文章中的问题,我也都会认真解答,看到有人阅读我的文章并有所收获,我真的挺欣慰,这就是写作的动力吧。
帮助别人的同时也是在帮助自己,自己学的技术和理解的内容都是有局限性的。通过写文章结识到了很多朋友,听听别人的分析和见解,我也能学到很多。
每次看到博客中有人留言都很激动,也会第一时间去回复。感谢下面的公众号大佬们之前无私的帮助,大家也可以关注一下他们,都是很nice
的大佬:
Java建设者、Java团长、程序猿石头、码象全栈、Java3y、JAVA小咖秀、Bella的技术轮子、石杉的架构笔记、武培轩、程序通事
Java中的线程池已经不是什么神秘的技术了,相信在看的读者在项目中也都有使用过。关于线程池的文章也是数不胜数,我们站在巨人的肩膀上来再次梳理一下。
本文还是保持原有的风格,图文解析,尽量做到多画图!全文共20000+字,建议收藏后细细品读,阅读期间搭配源码食用效果更佳!
-
ThreadPoolExecutor
有哪些状态,状态之间流转是什么样子的? -
Executors
工具类提供的线程池有哪些?有哪些缺陷? -
ThreadPoolExecutor
支持动态调整核心线程数、最大线程数、队列长度等一些列参数吗?怎么操作?
interruptIdleWorkers
含义是为空闲的线程设置中断标识,这里要清楚worker
什么时候空闲?我们在上面讲解runWorker()
方法时,执行task.run()
之前,要针对Worker
对象加锁,设置Worker
中的state
值为1,防止运行的worker
被添加中断标识。接着执行getTask()
方法,获取阻塞队列中的任务,如果是queue.take()
则会阻塞挂起当前线程,释放锁,此时线程处于空闲状态。如果是queue.pool()
返回为空,runWorker()
会释放锁,此时线程也是空闲状态。
执行interrupt()
后处于queue
阻塞的线程,会被唤醒,唤醒后,进入下一次自旋判断线程池状态是否改变,如果改变可能直接返回空,这里具体参看runWorker()
和getTask()
方法。
onShutdown()
也是一个扩展方法,需要子类去重写,这里代表当线程池关闭后需要做的事情。drainQueue()
方法是获取workQueue
中现有的的任务列表。
上面介绍过了,参见的参数是指ThreadPoolExecutor的构造参数,一般面试的时候都会先问这个,要解释每个参数的含义及作用。
通过AtomicInteger类型的变量ctl来存储,前3位代表线程池状态,后29位代表线程池中线程数量。
-
ThreadPoolExecutor
有哪些状态,状态之间流转是什么样子的?
这个问题就是考察execute()
的执行过程,只要看过源码就不会有问题。
-
Executors
工具类提供的线程池有哪些?有哪些缺陷?
这个主要是看runWorker()和getTask()两个方法的执行流程,当执行任务时调用runWorker()方法,执行完成后会继续从workQueue中获取任务继续执行,已达到线程复用的效果,当然这里还有一些细节,可以回头看看上面的源码解析。
最大的区别就是shutdown()会将线程池状态变为SHUTDOWN,此时新任务不能被提交,workQueue中还存有的任务可以继续执行,同时会像线程池中空闲的状态发出中断信号。
shutdownNow()方法是将线程池的状态设置为STOP,此时新任务不能被提交,线程池中所有线程都会收到中断的信号。如果线程处于wait状态,那么中断状态会被清除,同时抛出InterruptedException。
-
ThreadPoolExecutor
支持动态调整核心线程数、最大线程数、队列长度等一些列参数吗?怎么操作?
这篇线程池源码覆盖到了ThreadPoolExecutor
中大部分代码,我相信认真阅读完后肯定会对线程池有更深刻的理解。如有疑问或者建议可关注公众号给我私信,我都会一一为大家解答。
另外推荐一个我的up主朋友,他自己录制了好多学习视频并分享在B站上了,大家有时间可以看一下(PS:非恰饭非利益相关,良心推荐):