【线程池】线程池的ctl属性详解

news2024/11/18 4:50:11

目录

一、ctl介绍

二、线程池ctl源码

三、线程池ctl分析

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

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

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

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

四、线程池ctl如何管理池状态和线程数 


一、ctl介绍

ThreadPoolExecutor中有一个控制状态的属性叫ctl,它是一个AtomicInteger类型的变量,它包含两个概念:

  1. workerCount:表明当前有效的线程数
  2. runState:表明当前线程池的状态,是否处于Running,Shutdown,Stop,Tidying,Terminate五种状态。

为了把这两种状态放到一个int值(共32位)中保存,代码中限定了workerCount的值是2^29-1,因为还有五种状态需要表示,至少需要3位才能表示五种状态(3位二进制数最大能到6),所以会有29位来表示workerCount,而剩下的3位来表示当前线程池的状态。

从上面的代码中可以看出COUNT_BITS这个属性就是Integer.SIZE-3,也就是29。说明线程数所占位数为29位,而CAPACITY得到的就是1向左无符号移29位-1,得到的就是低28位全是1的536870911。而看到上图下面的五个状态,分别是-1,0,1,2,3向左无符号移29位。

位数计算

  • 从上图可以看到workerCountOf这个函数传入ctl之后,是通过ctl & CAPACITY操作来获取当前运行线程总数的。也就是RunningState | WorkCount & CAPACITY,算出来的就是低28位的值。因为CAPACITY得到的就是高3位(29-31位)位0,低28位(0-28位)都是1,所以得到的就是ctl中低28位的值。
  • 而runStateOf这个方法的话,算的就是RunningState | WorkCount & ~CAPACITY,高3位的值,因为~CAPACITY是CAPACITY的取反,所以得到的就是高3位(29-31位)为1,低28位(0-28位)为0,所以通过&运算后,所得到的值就是高3为的值。
  • 从而理解了ctl中是高3位作为状态值,低28位作为线程的线程数量来进行存储的原因。

二、线程池ctl源码

打开ThreadPoolExecutor的源码(我裁剪掉了一部分),一开始就会发现:

public class ThreadPoolExecutor extends AbstractExecutorService {
        /** 我以一个字节8位来简化解释线程池对运行状态和当前有效线程个数的原子管理方案
    
         * 线程池当中,用一个ctl原子变量包装了高3位的运行状态和低5位的线程个数
         *
         *   运行状态:  线程池初始化后,就处于该状态:此时,线程池可以接受新任务并且处理任务
         *   关闭状态:  调用shutdown()方法时,就处于该状态:此时,shutdown()方法之后不能再提交新任务,线程池会把shutdown()方法之前提交的任务按照线程池工作原理的步骤都处理完毕。(请参考我的博客:线程池工作原理)
         *   停止状态:  调用shutdownNow()方法时,就处于该状态:此时,shutdownNow()方法之后不能再提交新任务,线程池不处理已经提交到任务队列中的任务,线程池尝试中断正在执行的工作线程
         *   整理状态:  线程池内部自己使用的状态:当线程池queue任务队列为空,hashset<worker>为空时,就是该状态,该状态是由关闭状态/停止状态转变而来的。当处于整理状态时,线程池会调用terminated()钩子方法
         *   终结状态:  当钩子方法terminated()执行完毕之后,线程池由整理状态转变为终结状态。钩子方法是线程池自动调用的。
         *
         *   在线程池终结状态之前,可以调用awaitTermination()阻塞方法,使当前主线程阻塞,直至线程状态转变为终结状态
         */ 
    
     /**
     * The main pool control state, ctl, is an atomic integer packing
     * two conceptual fields
     *   workerCount, indicating the effective number of threads
     *   runState,    indicating whether running, shutting down etc
      *
      * The runState provides the main lifecycle control, taking on values:
      *
      *   RUNNING: Accept new tasks and process queued tasks
      *   SHUTDOWN: Don't accept new tasks, but process queued tasks
      *   STOP: Don't accept new tasks, don't process queued tasks, and interrupt in-progress tasks
      *   TIDYING: All tasks have terminated, workers is zero,the thread transitioning to state TIDYING
      *   TERMINATED: terminated() has completed
        *
        * RUNNING -> SHUTDOWN On invocation of shutdown(), perhaps implicitly in finalize()
        * (RUNNING or SHUTDOWN) -> STOP On invocation of shutdownNow()
        * SHUTDOWN -> TIDYING when both queue and pool are empty,will run the terminated() method
        * STOP -> TIDYING When pool is empty
        * TIDYING -> TERMINATED when the terminated() hook method has completed
        *
         * Threads waiting in awaitTermination() will return when the state reaches TERMINATED.
         */
        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; }
    
        .......
    
}

三、线程池ctl分析

负数的表示方法:补码表示法(原码的反码+1

我以8字节举例(同理适应于32位或64位机器)

上源码:我以8字节举例(同理适应于32位或64位机器)

private static final int COUNT_BITS = Integer.SIZE - 3;            //8-3=5 活跃线程支持5位来表示个数
private static final int CAPACITY   = (1 << COUNT_BITS) - 1; //1左移5位-1(1*2的5次方-1),也就是31个线程(低5位)   也就是00000001左移5位是00100000,然后再减00000001得到最终结果00011111将低5位标识线程数的部分保留

// runState is stored in the high-order bits
private static final int RUNNING    = -1 << COUNT_BITS;       // -1即11111111 左移5位后为11100000 表示运行状态(高3位)
private static final int SHUTDOWN   =  0 << COUNT_BITS;    //  0即00000000 左移5位后为00000000 表示关闭状态(高3位)
private static final int STOP       =  1 << COUNT_BITS;           //  1即00000001 左移5位后为00100000 表示停止状态(高3位)
private static final int TIDYING    =  2 << COUNT_BITS;         //  2即00000010 左移5位后为01000000 表示关闭状态(高3位)
private static final int TERMINATED =  3 << COUNT_BITS;   //  3即00000011 左移5位后为01100000 表示关闭状态(高3位)

不难发现,高3位很好的表示5种状态 000 SHUTDOWN,001 STOP,010 TIDYING,011 TERMINATED,111 RUNNING

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

假如:当前线程池是运行状态 rs = -1 并且有效线程是3个(ws),那么ctlOf(rs,wc)方法的逻辑是什么意思呢?rs | wc 的翻译如下:

11100000 (运行状态)

或             (0|1为1,1|1为1,0|0为0,也就是说,或的位运算,有1就为真)

00000011(线程个数)

的值为:11100011 表示ctl当前的值:有3个线程,线程池处于运行状态

该方法用于初始化ctl

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

由以上的ctlOf()举例分析,知晓了,初始化的ctl值为11100000,高3位表示线程池目前处于运行状态,低5位表示线程0个

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

这里的c是ctl.get()得到的原子值(AtomicInteger原子类中的volatile变量),也可以理解为当前ctl的值,这个值的高3位表示线程池的运行状态,低5位表示当前的线程个数。

c & ~CAPACITY 翻译如下:

假如c的值当前就是上面的举例:11100011 表示有3个线程,线程池处于运行状态

~CAPACITY 的运算即为:00011111求反,得值为11100000

c & ~CAPACITY

11100011(高3位表示运行状态)

与            (0&1为0,1&1为1,0&0为0,也就是说,与的位运算,有0必为假)

11100000

得值为:11100000 会发现,runStateOf()方法的目的就是高3位原是什么样,现运算后还是什么样,剔除掉了低5位的影响,我们通过runStateOf()方法拿到了纯的当前状态的值xxx00000 xxx刚好是:当初规定好的高3位表示当前的线程池状态

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

有了以上 c & ~CAPACITY 翻译后,这里就较好理解,下面翻译下 c & CAPACITY

假如c的值当前就是上面的举例:11100011 表示有3个线程,线程池处于运行状态

c & CAPACITY

11100011(高3位表示运行状态)

与            (0&1为0,1&1为1,0&0为0,也就是说,与的位运算,有0必为假)

00011111

四、线程池ctl如何管理池状态和线程数 

翻看ThreadPoolExecutor的源码会发现:

ctl的初始化:

private final AtomicInteger ctl = new AtomicInteger(ctlOf(RUNNING, 0)); 
private static int ctlOf(int rs, int wc) { return rs | wc; }

ctl在线程池运行期间,有大量的方法都调用了:

ctl.compareAndSet(expect, update); //这个操作是原子操作,表示设置当前ctl的值。

可参考AtomicInteger原子类的compareAndSet()方法

public final boolean compareAndSet(int expect, int update)

 相关文章:【线程池】Java的线程池
                  【线程池】Java线程池的核心参数
                  【线程池】Executors框架创建线程池        
                                  【线程池】ScheduledExecutorService接口和ScheduledThreadPoolExecutor定时任务线程池使用详解                 【线程池】线程池的拒绝策略(饱和策略) 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/705493.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

TensorFlow框架

TensorFlow框架 本文目录&#xff1a; 一、通过代码了解TensorFlow结构 1.1、TensorFlow实现一个加法运算代码 1.1.1、原生python加法运算 1.1.2、TensorFlow实现加法运算 1.1.3、TensorFlow实现加法运算 1.2、TensorFlow的Hello World 二、TensorFlow架构图 三、Tenso…

WebRTC Docker容器部署方案

文章目录 WebRTC简介WebRTC Docker容器部署优势方案&#xff08;mpromonet/webrtc-streamer&#xff09;步骤 WebRTC简介 WebRTC&#xff08;Web Real-Time Communication&#xff09;是一种开放的实时通信技术&#xff0c;它允许浏览器之间进行音频、视频和数据的实时传输。W…

第九十二天学习记录:C++核心:类和对象Ⅰ(五星重要)

C面向对象的三大特性为&#xff1a;封装、继承、多态 C认为万事万物都皆为对象&#xff0c;对象上有其属性和行为 封装 封装的意义 封装是C面向对象三大特性之一 封装的意义&#xff1a; 1、将属性和行为作为一个整体&#xff0c;表现生活中的事物 2、将属性和行为加以权限…

js判断文件类型详解

js判断文件类型详解 通过file的type属性判断 <input type"file" onchange"onchangecb(this)" /> <script> function onchangecb(e) {const file e.files[0];console.log(file.type); } </script>像html中input标签&#xff0c;就是根…

地下水数值模拟-Visual modflow Flex软件应用

地下水&#xff08;ground water&#xff09;&#xff0c;是指赋存于地面以下岩石空隙中的水&#xff0c;狭义上是指地下水面以下饱和含水层中的水。在国家标准《水文地质术语》&#xff08;GB/T 14157-93&#xff09;中&#xff0c;地下水是指埋藏在地表以下各种形式的重力水。…

基于协议判断目标机器是否出网

内网渗透中时常会碰到一些不出网的主机&#xff0c;不出网的原因有很多&#xff0c;如常见的有&#xff1a;没有设置网关、系统防火墙或者其他设备设置了出入站限制&#xff0c;只允许特定协议或端口出网等&#xff0c;遇到这种情况时可以用以下命令测试目标主机允许哪些协议出…

桥接模式的学习与使用

1、桥接模式的学习 当你需要将抽象部分与实现部分解耦&#xff0c;使它们可以独立地变化&#xff0c;而又能够灵活地组合在一起时&#xff0c;可以使用桥接模式。桥接模式通过将抽象和实现部分分离&#xff0c;使它们可以独立地进行扩展和变化&#xff0c;同时又能够在运行时动…

代码随想录二战day2

977有序数组的平方 力扣 思路&#xff1a; 第一&#xff1a; 和之前一样的&#xff0c;看见数组我们的第一想法就是使用双指针去解。这道题需要额外开辟一个答案数组去储存结果。 第二&#xff1a; 头指针指向第一个元素&#xff0c;尾指针指向最后一个元素。然后对两个元素分…

RocketMQ安装(Docker)

一、RocketMQ安装之docker 1.下载RockerMQ需要的镜像 docker pull rocketmqinc/rocketmq docker pull styletang/rocketmq-console-ng 2.启动NameServer服务 创建NameServer数据存储路径 mkdir -p /home/rocketmq/data/namesrv/logs /home/rocketmq/data/namesrv/store启动…

拾起王慧文的AI梦,美团冲向“光年之外”?

“十年&#xff0c;我需要休息休息&#xff0c;下一个十年&#xff0c;就托付给兄弟们了&#xff0c;感谢你们。” 2020年底&#xff0c;王慧文在朋友圈写下这句话时&#xff0c;外界本以为这位伴随中国互联网发展而持续创业20年的人物即将告别创业舞台。但是&#xff0c;一个…

Kubernetes创建集群—使用 Minikube 创建集群

一、使用 Minikube 创建集群 1、Kubernetes 集群 Kubernetes 协调一个高可用计算机集群&#xff0c;每个计算机作为独立单元互相连接工作。 Kubernetes 中的抽象允许你将容器化的应用部署到集群&#xff0c;而无需将它们绑定到某个特定的独立计算机。为了使用这种新的部署模型…

keepalived安装与使用(Nginx高可用)

一、Keepalived 简介&#x1f349; 1.什么是Keepalived &#xff1f;&#x1f95d; Keepalived一个基于VRRP 协议来实现的 LVS 服务高可用方案&#xff0c;可以利用其来解决单点故障。一个LVS服务会有2台服务器运行Keepalived&#xff0c;一台为主服务器&#xff08;MASTER&a…

Learn Mongodb DB功能命令索引等搜索 ⑤

作者 : SYFStrive 博客首页 : HomePage &#x1f4dc;&#xff1a; PHP MYSQL &#x1f4cc;&#xff1a;个人社区&#xff08;欢迎大佬们加入&#xff09; &#x1f449;&#xff1a;社区链接&#x1f517; &#x1f4cc;&#xff1a;觉得文章不错可以点点关注 &#x1f44…

layui框架学习(31:下拉菜单模块)

Layui的下拉菜单组件模块dropdown支持动态构建下拉菜单及右键菜单&#xff0c;不同于之前学习的页面元素中的菜单&#xff0c;后者主要是在页面中搭建菜单结构&#xff0c;然后通过设置layui提供的菜单相关的预设类对菜单结构进行样式渲染&#xff0c;而通过dropdown模块则是基…

【单片机】STM32单片机,RTC实时时钟,STM32F103C8T6,程序,万年历,数字时钟

文章目录 基础介绍rtc.hrtc.cmain.c 基础介绍 我以STM32F103C8T6为例&#xff0c;但STM32F103的RTC是通用的&#xff0c;STM32F103C8T6有一个原理图&#xff1a; https://qq742971636.blog.csdn.net/article/details/131288390 用纽扣电池给VBAT供电&#xff08;要共地&…

基于matlab使用多类掩码区域的卷积神经网络对人和汽车的各个实例进行分段(附源码)

一、前言 此示例展示了如何使用基于多类掩码区域的卷积神经网络 &#xff08;R-CNN&#xff09; 对人和汽车的各个实例进行分段。实例分割是一种计算机视觉技术&#xff0c;您可以在其中检测和定位对象&#xff0c;同时为每个检测到的实例生成分割图。 此示例首先演示如何使用…

shardingsphere-proxy 实现postgresql的单库分表

1、docker 安装zookeeper 1、拉取镜像 docker pull zookeeper2、运行容器 docker run -d -e TZ"Asia/Shanghai" -p 2181:2181 -v /home/sunyuhua/docker/zookeeper:/data --name zookeeper --restart always zookeeper3、查看容器是不是运行成功 docker exec -i…

Spring Boot 中的 @SendTo 注解

Spring Boot 中的 SendTo 注解 在 Spring Boot 中&#xff0c;SendTo 注解是一个非常有用的注解&#xff0c;它可以用于实现 WebSocket 的消息转发功能。本文将介绍 SendTo 注解的原理、使用方法和示例代码。 什么是 SendTo 注解 SendTo 注解是 Spring Boot 中用于将消息发送…

个人和企业如何有效保护IP地址?

随着互联网的快速发展&#xff0c;个人和企业对于保护IP地址的重要性越来越清晰。为了帮助读者更好地了解如何有效保护IP地址&#xff0c;以下将介绍几种方法&#xff0c;并提供一些相关的数据和专家意见。 使用防火墙是保护IP地址的一个重要手段。防火墙可以监控和过滤网络流量…

react native 使用Native Module、Intent、广播接收器 实现两个app之间的相互通信

一、react native版本环境: “react”: “18.1.0”, “react-native”: “0.70.6”, “node”: "14.18.2 二、发送端步骤: 在A app中注册一个Native Module模块,使用Intent 连接B app,sendBroadcast 发送广播传递数据。 (1)首先在 /android/app/src/main/java/com/j…