大家好,又见面了,我是你们的朋友全栈君。
在灯光的照耀下,餐厅的餐盘显得格外晶莹洁白,女朋友轻轻抿了一口红酒,问我说:“你经常提到线程池,线程池的原理到底是什么?”我愣了一下,心想女朋友今天怎么突然问这么专业的问题,但作为一个专业人士,我不能在她面前露怯啊。于是,我笑着说:“我给你讲讲我前同事老王的故事吧!”
老王是一位在北京打拼了十多年的程序员,由于年纪大了,加班不如年轻人,升迁无望,于是他带着积蓄回老家创业。他选择了洗浴行业,开了一家正规的洗浴中心。因为他之前常去的澡堂叫“清华池”,所以他给自己的洗浴中心取名“线程池”。
线程池洗浴中心开业后,老王发现有顾客想做足疗,于是招聘了一名足疗技师,增加了这项业务,增加了收入。随着做足疗的顾客增多,老王又招聘了四名足疗技师。但后来,老王发现店里已经有五名足疗技师,再招聘就支付不起更多的工资了。足疗技师忙不过来怎么办?老王想到了一个办法:让顾客排队,哪个足疗技师空闲了,就从队伍里叫一个顾客继续做。
周末一到,来洗浴中心的顾客比平时多了几倍,想做足疗的顾客排队时间过长,顾客们已经不耐烦了。老王马上做出反应,从其他洗浴中心紧急招聘了五名足疗技师,为队伍里的顾客做足疗,大大减少了排队时间。不过,有时生意太火爆,紧急招聘的技师也忙不过来,顾客排队时间还是很长,新的顾客来了,老王只能满脸赔笑地说:“您下次再来吧,下次给您找个好技师。”,把顾客拒之门外。周末过后,店里不能养闲人,老王就把紧急招聘的技师都辞退了。
立即学习“Java免费学习笔记(深入)”;
老王的生意越做越红火,很快就要开分店、融资上市、走上人生巅峰。既然这么成功,就让我们来复盘一下他的经营之道吧:
如果你了解了老王的经营之道,线程池就不难理解了,把顾客替换成任务,把足疗技师替换成线程,线程池洗浴中心就是线程池了,线程池的内部原理就是这样的:
梦醒铃铃铃,闹铃把我吵醒,原来是一场梦啊,我哪有什么女朋友?今天上午有一个面试,赶紧起床洗漱完毕,就出发了。在路上回想那个奇怪的梦,不妨再复习一下线程池的内部原理吧! 先看一下ThreadPoolExecutor类的execute方法:
代码语言:javascript代码运行次数:0运行复制```javascript public void execute(Runnable command) { if (command == null) throw new NullPointerException(); //获取clt,clt记录着线程池状态和运行线程数。 int c = ctl.get(); //运行线程数小于核心线程数时,创建线程放入线程池中,并且运行当前任务。 if (workerCountOf(c)
<code>
在execute方法中,多次调用的addWorker方法,再看一下这个方法:
<p>代码语言:javascript代码运行次数:0<svg fill="none" height="16" viewbox="0 0 16 16" width="16" xmlns="<a href="https://www.php.cn/link/c9041cfd2a40932691855abd98fd219a">http://www.w3.org/2000/svg"><path</a> d="M6.66666 10.9999L10.6667 7.99992L6.66666 4.99992V10.9999ZM7.99999 1.33325C4.31999 1.33325 1.33333 4.31992 1.33333 7.99992C1.33333 11.6799 4.31999 14.6666 7.99999 14.6666C11.68 14.6666 14.6667 11.6799 14.6667 7.99992C14.6667 4.31992 11.68 1.33325 7.99999 1.33325ZM7.99999 13.3333C5.05999 13.3333 2.66666 10.9399 2.66666 7.99992C2.66666 5.05992 5.05999 2.66659 7.99999 2.66659C10.94 2.66659 13.3333 5.05992 13.3333 7.99992C13.3333 10.9399 10.94 13.3333 7.99999 13.3333Z" fill="currentcolor"></path></svg>运行<svg fill="none" height="16" viewbox="0 0 16 16" width="16" xmlns="<a href="https://www.php.cn/link/c9041cfd2a40932691855abd98fd219a">http://www.w3.org/2000/svg"><path</a> clip-rule="evenodd" d="M4.5 15.5V3.5H14.5V15.5H4.5ZM12.5 5.5H6.5V13.5H12.5V5.5ZM9.5 2.5H3.5V12.5H1.5V0.5H11.5V2.5H9.5Z" fill="currentcolor" fill-rule="evenodd"></path></svg>复制```javascript
private boolean addWorker(Runnable firstTask, boolean core) { retry: for (;;) { //获取clt,clt记录着线程池状态和运行线程数。 int c = ctl.get(); //获取线程池的运行状态。 int rs = runStateOf(c); //线程池处于关闭状态,或者当前任务为null //或者队列不为空,则直接返回失败。 if (rs >= SHUTDOWN && ! (rs == SHUTDOWN && firstTask == null && ! workQueue.isEmpty())) return false; for (;;) { //获取线程池中的线程数 int wc = workerCountOf(c); //线程数超过CAPACITY,则返回false; //这里的core是addWorker方法的第二个参数, //如果为true则根据核心线程数进行比较, //如果为false则根据最大线程数进行比较。 if (wc >= CAPACITY || wc >= (core ? corePoolSize : maximumPoolSize)) return false; //尝试增加线程数,如果成功,则跳出第一个for循环 if (compareAndIncrementWorkerCount(c)) break retry; //如果增加线程数失败,则重新获取ctl c = ctl.get(); //如果当前的运行状态不等于rs,说明状态已被改变, //返回第一个for循环继续执行 if (runStateOf(c) != rs) continue retry; } } boolean workerStarted = false; boolean workerAdded = false; Worker w = null; try { //根据当前任务来创建Worker对象 w = new Worker(firstTask); final Thread t = w.thread; if (t != null) { final ReentrantLock mainLock = this.mainLock; mainLock.lock(); try { //获得锁以后,重新检查线程池状态 int rs = runStateOf(ctl.get()); if (rs largestPoolSize) largestPoolSize = s; workerAdded = true; } } finally { mainLock.unlock(); } if (workerAdded) { //启动线程,开始运行任务 t.start(); workerStarted = true; } } } finally { if (! workerStarted) addWorkerFailed(w); } return workerStarted;}</code>面试时,一个穿着格子衬衫的中年男子坐在我面前,对我说:“您好,我是今天的面试官。”我微笑地回应:“您好。”面试官面无表情地问我:“线程池一定用过吧,能说说线程池的内部原理吗?”我差点笑出声来,自信满满地说……
发布者:全栈程序员栈长,转载请注明出处:https://www.php.cn/link/90da3608667e990227e76560921e5fa7
以上就是给女朋友讲 : Java线程池的内部原理的详细内容,更多请关注php中文网其它相关文章!
每个人都需要一台速度更快、更稳定的 PC。随着时间的推移,垃圾文件、旧注册表数据和不必要的后台进程会占用资源并降低性能。幸运的是,许多工具可以让 Windows 保持平稳运行。
Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号