您当前的位置:首页 > 电脑百科 > 程序开发 > 语言 > JAVA

Java线程池的管理方法论

时间:2019-09-02 11:22:00  来源:  作者:

前言

各行各业都有基本功,例如医生,需要知道人体各个器官、各个系统的作用,知道细胞的作用、细菌和真菌的区别、病毒是怎么形成的,还得知道各种药的作用,如何对症下药等。

程序员世界里,也有着体现程序员基本功的东西,例如数据结构、算法、操作系统、网络等,特别是当今互联网,飞速发展下,迅速搞产品快速上线的时代已经不是主流,而且当下行业不景气;大厂们招聘标准上对基本功也是越来越看重,基本功的修炼已经刻不容缓。

所以,我想通过一种访谈的形式来慢慢揭开程序员各种基本功的细节,分享给一起同行的你们!!

嘉宾介绍

今天我们很荣幸的邀请到了一位JAVA世界的老前辈,ThreadPoolExecutor,Java线程团队Leader,被Doug Lea创造,2004年9月30日18:00PM,随着J2SE1.5的发布后,被大众熟知;在Java世界的15年里,他兢兢业业坚守着自己的岗位,在提高系统多核资源利用方面有着丰富的经验。

采访

作为线程团队的Leader,您是否了解您的团队成员?(ps:什么是线程?)

独家:Java线程池的管理方法论

 

其实我的团队成员都不是我招收进来的,他们都是由我的大BOSS(早期程序员开荒者)招进来;说到了解的话,这就得从我的大BOOS招来的操作系统老大说起;

操作系统指挥我们的程序干活主要靠以下几种算法:

  • 先来先服务和短作业(进程)优先调度算法
  • 高优先权优先调度算法
  • 优先权调度算法:非抢占式优先权算法和抢占式优先权算法
  • 高响应比优先调度算法
  • 基于时间片的轮转调度算法:时间片轮转法和多级反馈队列调度算法

大部分操作系统(如windowslinux)的任务调度是采用时间片轮转的抢占式调度方式,系统把所有就绪进程按先入先出的原则排成一个队列。新来的进程加到就绪队列末尾。每当执行进程调度时,进程调度程序总是选出就绪队列的队首进程,让它在CPU上运行一个时间片的时间。在一个时间片结束时,发生时钟中断,调度程序据此暂停当前进程的执行,将其送到就绪队列的末尾,并通过上下文切换执行当前的队首进程,进程可以未使用完一个时间片,就让出CPU

独家:Java线程池的管理方法论

 

进程是什么?

进程是一个具有一定独立功能的程序关于某个数据集合的一次运行活动。它是操作系统动态执行的基本单元,在传统的操作系统中,进程既是基本的分配单元,也是基本的执行单元。进程由内存空间(代码、数据、进程空间、打开的文件)和一个或多个线程组成。

介绍完上述的操作系统任务调度方式和进程的概念,我们再来聊聊我的团队成员到底是什么样的存在?

其实有进程就能满足一个程序的正常执行了,那么为什么还需要我和我的团队呢?其实是因为随着计算机的快速发展,对CPU的要求越来越高,进程之间切换的开销较大,已经无法满足越来越复杂的程序的要求了。我的大BOSS为了能支撑公司的发展,就叫操作系统BOSS去解决这个问题,操作系统BOSS就不得不寻找一种新人才,于是线程就诞生了。线程是程序执行中一个单一的顺序控制流程,是程序执行流的最小单元,是处理器调度和分派的基本单位。 有了线程也不代表代替了进程的地位,操作系统BOSS也比较聪明,让进程来指挥线程,一个进程可以有一个或多个线程,各个线程之间共享程序的内存空间(也就是所在进程的内存空间)。

一个标准的线程由线程ID、当前指令指针(PC)、寄存器和堆栈组成

您日常的工作有哪些呢?(ps:线程池到底做了什么?)

简单的说,我的工作就是来管理线程的,为啥需要管理呢?一般来说,我的团队成员也就那么10几个(ps:CPU密集型一般是N+1,I/O密集型一般是2N+1,其中N是CPU总核数),公司招一个人的成本也是很高的(ps:线程创建时间),而线程们也不会自己干活,他们没事的时候就休息着,等到有任务过来时,我就找正在休息的人来干活。

  • 线程的创建、销毁是非常耗时的,可能比实际执行任务的运行时间还要长。
  • 线程池就是对一定数量的线程保持其存活状态,不让其销毁,有新的任务来了就直接调用空闲线程来执行,这样就可以提升线程的运行效率。

能谈谈您具体是怎么管理您的团队成员么?(如何管理调度线程执行)

我的管理方式主要是依靠以下几个宝物:

  1. 状态控制器ctl:用于管理线程池状态和工作者线程个数
  2. 线程池大小配置corePoolSize和maximumPoolSize:决定了最大能运行多少线程
  3. 阻塞队列workQueue:当无空闲线程时,暂存在阻塞队列,等待poll出执行

状态控制器ctl

怎么去判断大家什么时候是休息状态,什么时候是工作状态呢;这就靠我的状态控制器ctl,它包含两部分:

  1. 线程池状态runState:通过这个状态我就能知道什么时候能分配任务,什么时候该下班休息
  2. 工作者线程个数:workCount

这里先介绍两个常量和获取这两部分信息的方式:

// 将32位int分割为3和29,前三位用于存储线程池状态,后面的位数表示工作者线程个数
int COUNT_BITS = Integer.SIZE - 3;
 
// 工作者线程个数,最大为2^29-1 
int CAPACITY = (1 << COUNT_BITS) - 1;
/**
1. runState:高三位来代表线程池状态,runState
2. workCount:表示工作者个数
*/
int runStateOf(int c) { return c & ~CAPACITY; }
int workerCountOf(int c) { return c & CAPACITY; }
int ctlOf(int rs, int wc) { return rs | wc; }

线程池状态主要有以下几种:

  • RUNNING = -1 << COUNT_BITS:允许接入新的task或处理workQueue中的task
  • SHUTDOWN = 0 << COUNT_BITS:不接受新的task,但是能处理workQueue中的task
  • STOP = 1 << COUNT_BITS:不接受新task,也不处理workQueue中的task,同时还会interrupt当前运行的task
  • TIDYING = 2 << COUNT_BITS:当状态变为TIDYING将会调起terminated()方法:所有task都被中断,workerCount=0;
  • TERMINATED = 3 << COUNT_BITS:terminated()方法执行完成

其中TERMINATED > TIDYING > STOP > SHUTDOWN > RUNNING

状态转换过程为:

  • RUNNING -> SHUTDOWN:shutdown()方法被调用时
  • (RUNNING or SHUTDOWN) -> STOP:shutdownNow()方法被调用时
  • SHUTDOWN -> TIDYING:当workQueue为空且线程池的运行线程为0时
  • STOP -> TIDYING:当线程池的运行线程为0时
  • TIDYING -> TERMINATED:当terminated()方法执行完成

如下图:

独家:Java线程池的管理方法论

 

线程调度

整个线程调度以来上述几个法宝:线程池大小、阻塞队列和状态控制器,具体思路如下:

  • 如果正在运行的线程数量小于 corePoolSize,那么马上创建线程运行这个任务;
  • 如果正在运行的线程数量大于或等于 corePoolSize,那么将这个任务放入队列;
  • 如果这时候队列满了,而且正在运行的线程数量小于 maximumPoolSize,那么还是要创建非核心线程立刻运行这个任务;
  • 如果队列满了,而且正在运行的线程数量大于或等于 maximumPoolSize,那么线程池会交由RejectedExecutionHandler来处理

如下图:

独家:Java线程池的管理方法论

 

下面让我们看看具体实现:

独家:Java线程池的管理方法论

 

addWorker:创建一个新的Worker用于执行Runnable

独家:Java线程池的管理方法论

 


独家:Java线程池的管理方法论

 

Worker的run方法实际调用的是ThreadPoolExecutor#runWorker方法:如果工作者本身带有task则执行,否则会从阻塞队列workQueue中poll中一个task进行执行

独家:Java线程池的管理方法论

 

 



Tags:Java 线程池   点击:()  评论:()
声明:本站部分内容及图片来自互联网,转载是出于传递更多信息之目的,内容观点仅代表作者本人,如有任何标注错误或版权侵犯请与我们联系(Email:2595517585@qq.com),我们将及时更正、删除,谢谢。
▌相关推荐
之前我们介绍了线程池的四种拒绝策略,了解了线程池参数的含义,那么今天我们来聊聊Java 中常见的几种线程池,以及在jdk7 加入的 ForkJoin 新型线程池 首先我们列出Java 中的...【详细内容】
2020-11-05  Tags: Java 线程池  点击:(91)  评论:(0)  加入收藏
随着计算机行业的飞速发展,摩尔定律逐渐失效,多核CPU成为主流。使用多线程并行计算逐渐成为开发人员提升服务器性能的基本武器。J.U.C提供的线程池ThreadPoolExecutor类,帮助开...【详细内容】
2020-05-05  Tags: Java 线程池  点击:(44)  评论:(0)  加入收藏
前言各行各业都有基本功,例如医生,需要知道人体各个器官、各个系统的作用,知道细胞的作用、细菌和真菌的区别、病毒是怎么形成的,还得知道各种药的作用,如何对症下药等。在程序员...【详细内容】
2019-09-02  Tags: Java 线程池  点击:(182)  评论:(0)  加入收藏
前言谈到 Java 的线程池最熟悉的莫过于 ExecutorService 接口了,jdk1.5 新增的 java.util.concurrent 包下的这个 api,大大的简化了多线程代码的开发。而不论你用 FixedThread...【详细内容】
2019-08-29  Tags: Java 线程池  点击:(187)  评论:(0)  加入收藏
这篇文章结合Doug Lea大神在JDK1.5提供的JCU包,分别从线程池大小参数的设置、工作线程的创建、空闲线程的回收、阻塞队列的使用、任务拒绝策略、线程池Hook等方面来了解线...【详细内容】
2019-07-23  Tags: Java 线程池  点击:(303)  评论:(0)  加入收藏
▌简易百科推荐
面向对象的特征之一封装 面向对象的特征之二继承 方法重写(override/overWrite) 方法的重载(overload)和重写(override)的区别: 面向对象特征之三:多态 Instanceof关键字...【详细内容】
2021-12-28  顶顶架构师    Tags:面向对象   点击:(2)  评论:(0)  加入收藏
一、Redis使用过程中一些小的注意点1、不要把Redis当成数据库来使用二、Arrays.asList常见失误需求:把数组转成list集合去处理。方法:Arrays.asList 或者 Java8的stream流式处...【详细内容】
2021-12-27  CF07    Tags:Java   点击:(3)  评论:(0)  加入收藏
文章目录 如何理解面向对象编程? JDK 和 JRE 有什么区别? 如何理解Java中封装,继承、多态特性? 如何理解Java中的字节码对象? 你是如何理解Java中的泛型的? 说说泛型应用...【详细内容】
2021-12-24  Java架构师之路    Tags:JAVA   点击:(5)  评论:(0)  加入收藏
大家好!我是老码农,一个喜欢技术、爱分享的同学,从今天开始和大家持续分享JVM调优方面的经验。JVM调优是个大话题,涉及的知识点很庞大 Java内存模型 垃圾回收机制 各种工具使用 ...【详细内容】
2021-12-23  小码匠和老码农    Tags:JVM调优   点击:(12)  评论:(0)  加入收藏
前言JDBC访问Postgresql的jsonb类型字段当然可以使用Postgresql jdbc驱动中提供的PGobject,但是这样在需要兼容多种数据库的系统开发中显得不那么通用,需要特殊处理。本文介绍...【详细内容】
2021-12-23  dingle    Tags:JDBC   点击:(13)  评论:(0)  加入收藏
Java与Lua相互调用案例比较少,因此项目使用需要做详细的性能测试,本内容只做粗略测试。目前已完成初版Lua-Java调用框架开发,后期有时间准备把框架进行抽象,并开源出来,感兴趣的...【详细内容】
2021-12-23  JAVA小白    Tags:Java   点击:(11)  评论:(0)  加入收藏
Java从版本5开始,在 java.util.concurrent.locks包内给我们提供了除了synchronized关键字以外的几个新的锁功能的实现,ReentrantLock就是其中的一个。但是这并不意味着我们可...【详细内容】
2021-12-17  小西学JAVA    Tags:JAVA并发   点击:(11)  评论:(0)  加入收藏
一、概述final是Java关键字中最常见之一,表示“最终的,不可更改”之意,在Java中也正是这个意思。有final修饰的内容,就会变得与众不同,它们会变成终极存在,其内容成为固定的存在。...【详细内容】
2021-12-15  唯一浩哥    Tags:Java基础   点击:(17)  评论:(0)  加入收藏
1、问题描述关于java中的日志管理logback,去年写过关于logback介绍的文章,这次项目中又优化了下,记录下,希望能帮到需要的朋友。2、解决方案这次其实是碰到了一个问题,一般的情况...【详细内容】
2021-12-15  软件老王    Tags:logback   点击:(19)  评论:(0)  加入收藏
本篇文章我们以AtomicInteger为例子,主要讲解下CAS(Compare And Swap)功能是如何在AtomicInteger中使用的,以及提供CAS功能的Unsafe对象。我们先从一个例子开始吧。假设现在我们...【详细内容】
2021-12-14  小西学JAVA    Tags:JAVA   点击:(22)  评论:(0)  加入收藏
最新更新
栏目热门
栏目头条