商城首页欢迎来到中国正版软件门户

您的位置: 首页 > 文章列表 > 系统应用 > 编程之美!从线程池状态管理来看二进制操作之美

编程之美!从线程池状态管理来看二进制操作之美

  发布于2026-08-20 阅读(0)

扫一扫,手机访问

二进制操作在框架设计中被频繁使用,使用二进制在不同场景有提升计算速度较少内存占用等多种优点;

下面,我们依据线程池的状态管理,来看下怎么通过操作二进制对状态进行管理,过程中会发现编程之美~

线程池状态

首先,为了文章的完整性,我们还是先了解一下线程池的状态,总结如下如:

线程池状态分为5种RUNNINGSHUTDOWNSTOPTIDYINGTERMINATED

状态代表的含义

  • RUNNING:(运行)接收新task,并且处理正在排队的task,不中断正在执行的任务
  • SHUTDOWN:(关闭)不接受新的task,只处理正在排队的task,不中断正在执行的任务
  • STOP:(停止)不接受新的task,也不处理正在排队的task,并且中断正在执行的任务
  • TIDYING:(整理)所有的task都已经终止,上述提到的workCount当前活跃线程数为0,被中断的任务和正在排队的任务执行当前任务的terminated()钩子方法
  • TERMINATED:(已终止)标识上述的TIDYING的过程结束,标识当前线程池成功完全停止的状态

状态转换

大致的流程就是:

RUNNING --> SHUTDOWN --> STOP --> TIDYING --> TERMINATED

上述流程是一个单方向的顺序,也就是说不会出现类似于STOP --> SHUTDOWN 这种情况;

另外,并不是每一个状态多必须经过的;

什么时候进行线程池的状态转换呢?

  • RUNNING -> SHUTDOWN:调用终止线程的方法shutdown()
  • RUNNING or SHUTDOWN -> STOP:调用shutdownNow()方法后,不管当前在RUNNING状态还是SHUTDOWN状态,都是直接转为STOP状态
  • SHUTDOWN -> TIDYING:SHUTDOWN状态下当等待队列 和 正在执行的任务 都为空时,状态转为TIDYING
  • STOP -> TIDYING:STOP状态下当正在执行的任务全部中断完毕后,状态转为TIDYING
  • TIDYING -> TERMINATED:TIDYING状态下当所有的terminated()钩子方法全部执行完毕后,状态转为TERMINATED,线程池关闭完毕!

管理线程池状态

线程池中管理线程池状态 和 线程池当前活跃线程数,是通过一个AtomicInteger变量来管理这两个状态的

什么? 一个变量管理两个这么不相干的状态? 对的;

CTL变量何许人也

让我们来看一下线程池针对这部分的实现:

    private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0));
private static final int COUNT_BITS = Integer.SIZE - 3;
private static final int CAPACITY = (1 << COUNT_BITS) - 1;

// runState is stored in the high-order bits
private static final int RUNNING = -1 << COUNT_BITS;
private static final int SHUTDOWN = 0 << COUNT_BITS;
private static final int STOP = 1 << COUNT_BITS;
private static final int TIDYING = 2 << COUNT_BITS;
private static final int TERMINATED = 3 << COUNT_BITS;

// Packing and unpacking ctl
private static int runStateOf(int c) { return c & ~CAPACITY; }
private static int workerCountOf(int c) { return c & CAPACITY; }
private static int ctlOf(int rs, int wc) { return rs | wc; }
private static boolean isRunning(int c) { return c < SHUTDOWN;}

下面,我们来剖析一下上述的实现: 线程池包含5种状态如下:具体线程的状态代表的含义和状态的转换,下面会有讲解:

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

private static final int RUNNING = -1 << COUNT_BITS;
private static final int SHUTDOWN = 0 << COUNT_BITS;
private static final int STOP = 1 << COUNT_BITS;
private static final int TIDYING = 2 << COUNT_BITS;
private static final int TERMINATED = 3 << COUNT_BITS;

我们知道在java中 int 类型占用4个字节32位存储, 上述的几种状态: 底层存储二进制为:

1111 1111 1111 1111 1111 1111 1111 1111(-1) 0000 0000 0000 0000 0000 0000 0000 0000(0) 0000 0000 0000 0000 0000 0000 0000 0001(1) 0000 0000 0000 0000 0000 0000 0000 0010(2) 0000 0000 0000 0000 0000 0000 0000 0011(3)

左移<COUNT_BITS = Integer.SIZE - 3 也就是 COUNT_BITS = 29,改句子说明用32位的前3位存储线程池的状态 后29位存储线程池中当前线程的个数, << COUNT_BITS后,变为下面的二进制:

1110 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0000 0010 0000 0000 0000 0000 0000 0000 0000 0100 0000 0000 0000 0000 0000 0000 0000 0110 0000 0000 0000 0000 0000 0000 0000

我们可以看到,前三位存储的是 标识线程状态的二进制

对于初始化存储这些状态的变量AtomicInteger ctl

private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0))

初始化AtomicInteger变量ctl,其中ctlOf(RUNNING, 0) 代码为:

private static int ctlOf(int rs, int wc) { return rs | wc; }

其中rs标识线程池当前状态,wc为work count标识当前工作线程的数量

上述传入的是ctlOf(RUNNING, 0) ,当前状态为RUNING也就是1110 0000 0000 0000 0000 0000 0000 0000 ,wc为0,也就是当前工作线程数为0,其二进制为0000 0000 0000 0000 0000 0000 0000 0000 ,做"|"或操作,即

1110 0000 0000 0000 0000 0000 0000 0000 | 0000 0000 0000 0000 0000 0000 0000 0000 = 1110 0000 0000 0000 0000 0000 0000 0000

上述得到的结果1110 0000 0000 0000 0000 0000 0000 0000就标识,当前线程池状态为RUNNING,线程池活跃线程个数为0!

如何管理?

通过上述创建的ctl变量获取 线程池当前状态 和 线程中活跃线程个数 这两个状态:

获取线程池当前状态,我们可以想一下该如何获取呢? 现在知道的是ctl的前3位是线程池的状态,那我们直接构造一个前三位为1,后29位为0的int即可,然后取余就可以了呗,下面看下源码的实现,就是如此: 使用方法runStateOf

 private static int runStateOf(int c)     { return c & ~CAPACITY; }

其中CAPACITY = (1 << COUNT_BITS) - 1 转化为二进制为: 0001 1111 1111 1111 1111 1111 1111 1111 取反"~"后,二进制为: 1110 0000 0000 0000 0000 0000 0000 0000 也就是将前3位全部变为1,后面全部变为0; 接下来,传入的ctl变量和~CAPACITY做“&”操作,只会保留ctl变量的前3位变量,后29位变量全部为0;

例如:一个标识当前状态为STOP状态的线程池和当前活跃线程数为3的ctl变量为: 0010 0000 0000 0000 0000 0000 0000 0011 和上述得到的1110 0000 0000 0000 0000 0000 0000 0000做“&”操作后得到: 0010 0000 0000 0000 0000 0000 0000 0000 和上述分析的STOP的状态的二进制相同! 即获得了当前线程的状态!

获取线程池当前状态,也很简单,我们知道ctl变量的32的后29位存储的是当前活跃线程数,直接构造一个前三位为0,后29位为1的int即可,然后取余就可以获取到了 使用方法workerCountOf

private static int workerCountOf(int c)  { return c & CAPACITY; }

上述知道CAPACITY为:0001 1111 1111 1111 1111 1111 1111 1111

比如说,一个标识当前状态为STOP状态的线程池,它和当前活跃线程数为3的ctl变量分别是:0010 0000 0000 0000 0000 0000 0000 00110001 1111 1111 1111 1111 1111 1111 1111 。这两个变量进行取与操作后得到:0000 0000 0000 0000 0000 0000 0000 0011 ,这个结果就标识着当前线程池中活跃线程数量为3!

一些方法

1、计算ctl的值

方法:

private static int ctlOf(int rs, int wc) { return rs | wc; }

其中,入参rs代表当前线程状态,wc代表当前活跃线程数,取“|”或即可 上述代码不出现问题的前提是:rs只使用的前3位,wc只使用了后29位!

2、判断当前线程池是否正在运行

方法:

private static boolean isRunning(int c) {  return c <小于SHUTDOWN;}值即可!

上述我们知道,5中状态只有RUNNING小于0,SHUTDOWN状态等于0,其他的都是大于0的,所以我们直接把给定的ctl值小于SHUTDOWN值即可!

最后

上述,我们介绍了 线程池的状态 管理部分,主要通过不同位置的二进制来进行标识不同的状态,工作学习还会发现更多巧妙美妙的设计,等待着作为程序员我们去发现;

本文转载于:https://apiv1.oschina.net/oschinapi/blog/detail?id=4830404 如有侵犯,请联系zhengruancom@outlook.com删除。
免责声明:正软商城发布此文仅为传递信息,不代表正软商城认同其观点或证实其描述。
  • 字节跳动基于ClickHouse优化实践之Upsert 正版软件
    字节跳动基于ClickHouse优化实践之Upsert
    更多技术交流、求职机会、试用福利,欢迎关注字节跳动数据平台微信公众号,回复【1】进入官方交流群相信大家都对大名鼎鼎的ClickHouse有一定的了解,它强大的数据分析性能让人印象深刻。但在字节大量生产使用中,发现了ClickHouse依然存在了一定的限制。例如:缺少完整的upsert和delete操
    1小时前 07:25 0
  • 开源图编辑库NebulaGraphVEditor的设计思路分享 正版软件
    开源图编辑库NebulaGraphVEditor的设计思路分享
    本文首发于 NebulaGraph 公众号NebulaGraph VEditor 是一个拥有高性能、高可定制的所见即所得图可视化编辑器前端库。NebulaGraph VEditor 底层基于 SVG 绘图,它通过合理抽象代码结构以易于二次开发和自定义绘制,极适用于审批流,工作流,血缘关系,ETL 处
    1小时前 07:25 0
  • 首批成员!博云入选信通院“可信边缘计算推进计划” 正版软件
    首批成员!博云入选信通院“可信边缘计算推进计划”
    8 月 10 日,由中国信息通信研究院和中国通信标准化协会主办的“2022 数字化转型发展高峰论坛”在北京召开。会上,“可信边缘计算推进计划”正式启动,江苏博云科技股份有限公司(以下简称:博云)成功入选首批成员单位。“可信边缘计算推进计划”由中国信通院云计算与大数据研究所发起,它汇聚了产、学、研、用
    1小时前 07:25 0
  • 【云原生】快速了解Kubernetes 正版软件
    【云原生】快速了解Kubernetes
    在云原生技术发展的浪潮之中,Kubernetes伴随着容器技术的发展,成为了目前云时代的“操作系统”。Kubernetes作为容器集群管理系统和云原生领域的关键项目,已经是云原生时代最需要理解与实践的核心技术。但技术的发展从来都不是一蹴而就,Kubernetes的诞生也有其对
    1小时前 07:24 0
  • 百度用户产品流批一体的实时数仓实践 正版软件
    百度用户产品流批一体的实时数仓实践
    导读:本文主要介绍如何基于流批一体的技术架构构建实时数仓,在严格的资源成本限制下,满足业务对于数据时效性、准确性的需求。文章整体包含4个部分,首先会介绍下大数据架构演进,从经典架构到Lambda架构再到Kappa架构;然后会介绍下我们做流批一体实时数仓的背景,旧架构面临的主要问题;第三会介绍下我们流
    1小时前 07:24 0