专注于 JetBrains IDEA 全家桶,永久激活,教程
持续更新 PyCharm,IDEA,WebStorm,PhpStorm,DataGrip,RubyMine,CLion,AppCode 永久激活教程

JDK线程池之位运算的艺术

想要成为优秀的Java程序员,首要条件就是要熟悉JUC包,而ThreadPoolExecutor这个类又是JUC包的重中之重和集大成者(runnable、阻塞队列、AQS、同步锁、Condition、Atomic原子操作,乐观所,都有涉及)。很多朋友对于ThreadPoolExecutor的构造方法、excute()方法的执行逻辑判断三部曲也都耳熟能详。但我今天想讨论的问题和ThreadPoolExecutor至关重要,但又和并发编程关系不大。

抛出问题

45_1.png

这个ctl变量是个什么鬼???

ctl的用途

我们首先来翻译一下官方给出的注释

45_2.png

ctl的内部构造

我们知道Integer表示为二进制,可以理解位一个31位的数组,如下图所示:

45_3.png

private static final int COUNT_BITS = Integer.SIZE - 3;

据此可知,COUNT_BITS为29; 也就是说RUNNING的值为-1左移29位, 我们知道-1的原码是1000……1, 所以反码是1111……110, 补码就是1111……111, 关于反码补码不清楚的可以看这里传送门 所以RUNNING二进制如下图所示:

45_4.png同理可知SHUTDOWN二进制如下图所示:

45_5.pngSTOP:

45_6.pngTIDYING:

45_7.pngTERMINATED:

45_8.png

如何判断线程池工作状态

我们addWorker方法入手

45_9.png拿到ctl的值, 然后继续进入这个runStateOf方法:

45_10.pngCAPACITY的值是1右移29位,然后减去1,再取反,表示成二进制: 45_11.png面对这样的值,敏感的同学都知道,一定是用来做掩码的,在HashMap的源码中,在计算某个待插入的数字归属于哪个桶的时候,也有类似的掩码做与运算。 但我们这边是做或运算,所以我们这里的c,换算成二进制后,右边的29位,无论是什么数字,或者换句话说,不管你的workerCount是多少,都会全部抹0,而高位的表示runState的两位数字,无论是什么数字,都会保持原样。因此经过runStateOf方法后的返回值,就可以直接与RUNNING、SHUTDOWN、STOP、TIDYING、TERMINATED这些静态常量相比较,以此判断线程池的运行状态了。

如何获取线程池当前worker数

45_12.png还是CAPACITY,这次没有取反,所以表示成二进制是:

45_13.pngc与其做与运算,左侧两个表示runState的值被抹零,右侧29位不变,完美表示workerCount

细节

这里还有个设计的小细节,为什么只有RUNNING设置为负数,SHUTDOWN设置为0呢? 我们线程池判断状态的时候,最常用的一定是看他是否是运行状态,因此ThreadPoolExecutor类提供了isRunning方法:

45_14.png这个方法实现是如此简单,直接看ctl是否小于SHUTDOWN,也就是0,因为如果是RUNNING状态的线程池,ctl的最高位无论如何是1,也就是说ctl无论如何都是个负数。至此深感作者真是考虑太周到了!这些小细节都足以让人品玩。

总结

在JDK和很多优秀开源组件的源码中,都有不少与、或、非、取反、亦或、左移、右移、无符号右移的二进制运算,究其原因是为了更好的性能。 同时,在很多情况下,巧用二进制,可以实现很多神奇的功能,比如Redis中基于BitMap结构的布隆过滤器等。

文章永久链接:https://tech.souyunku.com/31469

未经允许不得转载:搜云库技术团队 » JDK线程池之位运算的艺术

JetBrains 全家桶,激活、破解、教程

提供 JetBrains 全家桶激活码、注册码、破解补丁下载及详细激活教程,支持 IntelliJ IDEA、PyCharm、WebStorm 等工具的永久激活。无论是破解教程,还是最新激活码,均可免费获得,帮助开发者解决常见激活问题,确保轻松破解并快速使用 JetBrains 软件。获取免费的破解补丁和激活码,快速解决激活难题,全面覆盖 2024/2025 版本!

联系我们联系我们