Java线程池

基本原理

线程池基本常识

线程池(Thread Pool)是一种基于池化思想管理线程的工具。线程频繁的创建、销毁会产生大量的系统内核调用,消耗CPU资源。用线程池来维护多个线程的生命周期,一方面可以避免线程频繁地创建销毁,另一方面也可以解决线程的调度管理问题。

使用线程池带来一系列好处:

    降低资源消耗:池化技术重复利用已创建的线程,从而降低线程创建和销毁造成的损耗。

    提高响应速度:任务到达时,如果有空闲线程,则任务无须再等待线程创建。

    线程可管理:线程交由线程池统一管理,可以避免线程无限制创建造成的资源损耗,以及一些线程分布不合理造成的资源调度失衡。

    更强大的功能:面向开发人员更加灵活强大的操作。如定时执行或者延时执行。

池化思想在很多领域都有广泛应用,其他几种比较典型的使用策略:

    1.内存池 2.连接池 3.实例池

线程池核心设计和实现

本文我们主要讨论java的线程池。核心实现类是ThreadPoolExcutor。我们基于jdk1.8论述。

线程池类继承简图

上图是一个简略的类继承图。线程池基本思想是:将任务提交和任务执行解耦。用户只需要提供一个runnable对象,然后将任务交给执行器Executor,无需关注线程如何创建,执行过程。

ExecutorService则为执行器增加了一些能力:

    扩充执行任务的能力,补充可以为一个或者一批异步任务生成Future的方法;

    提供了控制线程池的方法,例如停止线程池执行。

ExcutorAbstractService则是抽象实现类,将执行任务的流程封装起来,保证下层实现时能够简单且正确。

ThreadPoolExecutor的运行如下:

线程池运行图概览

线程池主要分为两部分:任务管理和线程管理。

任务管理部分主要负责线程的流转:

    1.直接申请线程执行任务;

    2.放到等待队列等待执行;

    3.直接拒绝该任务。

线程管理主要负责线程分配及回收。

线程池自身生命周期

线程池运行的状态,是由线程池内部维护的。线程池内部使用一个变量维护两个值:运行状态(runState)和线程数量(workerCount)。

线程池中定义的运行状态有5种:

线程池状态

线程池运行状态转换:

线程池状态转换

任务管理

任务调度

任务的调度都由execute方法完成,这部分完成的工作包括:检查线程池的运行状态、线程运行数、运行策略,从而决定接下来的流程,是直接申请线程,还是放到缓冲队列,亦或者直接拒绝该任务。执行流程如下:

    1.确定线程池是RUNNING状态,否则直接拒绝。

    2.正在运行的线程数 < corePoolSize,直接创建并启动一个新线程执行任务。

    3.正在运行的线程数 >=corePoolSize,且线程池内阻塞队列未满,则任务放入队列。

    4.阻塞队列已满,正在运行的线程>=corePoolSize && 正在运行的线程数 < maximumPoolSize,创建并启动一个线程来执行任务。

线程池阻塞队列已满, 正在运行的线程数 >= maximumPoolSize,根据拒绝策略处理该任务,默认方式是抛出异常。

任务调度流程图:

任务调度流程图

任务缓冲

线程池本质是对任务和线程的管理,做到这一点最关键的思想就是任务和线程解耦。线程池采用生产者消费者模式,通过阻塞队列实现。阻塞队列缓存任务,工作线程从阻塞队列获取任务。

BlockingQueue(阻塞队列):当队列为空时,消费线程会等待队列非空;当队列满时,生产线程会等待队列可用。

常用阻塞队列

任务申请

当工作线程空闲后,会尝试获取线程,获取过程中会做如下判断:

    1.线程池是否已经停止运行,如果是,则返回null

    2.线程数现阶段是否过多,如果超出设置数量,会返回null

    3.线程如果一直获取不到任务,就会被回收掉,从而保证线程数量处在一个可控范围内。

核心方法如下:

任务拒绝

任务拒绝是线程池的保护策略,当线程池达到最大容量(缓存队列已满且线程数达到设置最大值),会对任务进行拒绝。拒绝策略是一个接口:

public interface RejectedExecutionHandler{

void rejectedExecution(Runnabler,ThreadPoolExecutor executor);

}

用户可以自定义拒绝策略,或者采用jdk提供的策略:

java提供的几种拒绝策略

线程管理

worker线程

worker类

线程池通过一张Hash表去维护线程的引用,这样可以通过添加引用、移除引用来控制线程的生命周期。

worker通过继承AQS来实现独占锁的功能,使用不可重入锁来控制线程的执行状态。

    1.lock方法一旦获取了独占锁,就表示线程正在执行任务。

    2.如果正在执行任务,则线程不应该中断。

    3.如果线程不是独占锁状态,就说明他是空闲状态,可以中断该线程。

    4.线程池在执行shutdown方法或tryTerminate方法时会调用interruptIdleWorkers方法来中断空闲的线程,interruptIdleWorkers方法会使用tryLock方法来判断线程池中的线程是否是空闲状态;如果线程是空闲状态则可以安全回收。

worker线程增加

addWorker方法增加线程,这个方法里面有两个参数:firstTask、core。firstTask用于指定新增的线程执行的第一个任务,该参数可以为空;core=true表示增加线程是判断当前活动线程数是否少于corePoolSize,core=false表示新增线程需要判断当前活动线程数是否少于maximumPoolSize。

worker线程回收

线程回收主要依赖JVM自动回收,线程池做的工作只是维护线程的引用,防止线程被回收,当一些线程需要被回收时,只要删除他的引用即可。Worker被创建出来后,就会不断轮询获取任务执行。当Worker无法获取任务时,就会结束循环,Worker会主动消除自己身上的引用。

worker线程退出

worker线程执行任务

runWorker方法执行任务,执行过程:

    1.while循环不断通过getTask()获取任务

    2.getTask()方法从阻塞队列中取任务。

    3.如果线程池正在停止,则保证当前线程是中断状态,否则要保证当前线程不是中断状态。

    4.执行任务。

    5.如果getTask()为null则跳出循环,销毁线程。

java提供的几种线程池

java提供的几种线程池

相关文章:

Java线程池实现原理及其在美团业务中的实践

深入理解Java线程池:ThreadPoolExecutor

jdk1.8 源码

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,847评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,208评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,587评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,942评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,332评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,587评论 1 218
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,853评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,568评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,273评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,542评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,033评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,373评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,031评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,073评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,830评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,628评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,537评论 2 269

推荐阅读更多精彩内容