前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java线程池前传

Java线程池前传

作者头像
shysh95
发布2021-04-23 13:02:14
2600
发布2021-04-23 13:02:14
举报
文章被收录于专栏:shysh95

摘要

  1. 为什么要使用线程池
  2. 线程池的总体设计
  3. 线程池的生命周期

1. 为什么要使用线程池

通过线程池,我们可以预留一部分线程,不必要每次创建,使用线程池可以带来以下优点:

  • 降低资源消耗,通过重复利用线程,降低每次线程创建销毁带来的损耗
  • 提高系统响应速度,当我们提交任务时,可以利用已有的线程直接执行,不必等待线程的创建
  • 方便管理线程,通过线程池我们可以管理线程,包括线程的数量,线程需要占用系统资源,如果不加以控制肆意创建,可能会导致系统的崩溃,降低系统的稳定性

2. 线程池的总体设计

上图是线程池的简单类图,ThreadPoolExecutor是整个线程池的核心类,但在介绍它之前我们需要先看一下他实现的接口和继承的抽象类。

2.1 Executor接口

Executor接口中只有一个方法,如下:

代码语言:javascript
复制
public interface Executor {

    void execute(Runnable command);
}

该方法其实就是执行一个Task,用来代替普通线程的创建和启动,后面我们会讲解ThreadPoolExecutor中的实现。

2.2 ExecutorService接口

ExecutorService接口继承自Executor接口,在Executor接口功能上,增加了线程池关闭功能、以及为一个异步或一批异步任务生成Future的方法,增加的方法如下图:

2.3 AbstractExecutorService抽象类

AbstractExecutorService抽象类实现了ExecutorService接口,并且实现了ExecutorService接口中的submit、invokeAny、invokeAll方法。

2.4 ThreadPoolExecutor类

ThreadPoolExecutor是线程池的实现类,里面包含很多重要的方法以及属性、和一些特定的内部类,我会在后面剖析线程池的实现过程中逐渐提到这些类和属性。

3. 线程池的生命周期

线程池的生命周期如下表:

状态

描述

RUNNING

运行状态,执行现有任务和阻塞队列中的任务,并且可以接收新的任务

SHUTDOWN

关闭状态,可以执行现有任何和阻塞队列中的任务,但不接收新的任务

STOP

停止状态,中断正在处理任务的线程,不再接收和处理阻塞队列中任务

TIDYING

所有任务已经终止,workCount(工作线程数)为0

TERMINATED

terminated()方法执行完成以后进入该状态

生命周期的转换如下图:

通过上表和上图我们已经清楚的知道了线程池的生命周期,那么线程池的生命周期在ThreadPoolExecutor是如何维护的呢?

代码语言:javascript
复制
    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这个属性来表示,但是ctl属性不仅仅维护了线程池的运行状态,还维护了线程数量,那么它是如何同时表示这两个属性的呢?

ctl的高3位保存线程池的运行状态,低29位保存了线程的数量。使用一个变量来存储两个属性,可以避免在做决策时出现不一致的情况,不必为了维护两者的一致性占用锁资源,因为在整个线程的视线中会经常性同时判断工作线程数量和线程池运行状态。

上述属性中COUNT_BITS的值29,CAPACITY就是1左移29位然后减1(536870911),CAPACITY就是最大线程数,如下:

代码语言:javascript
复制
00011111 11111111 11111111 11111111

下面的RUNNING、SHUTDOWN、STOP、TIDYING和TERMINATED属性代表线程池的状态。

runStateOf用来计算线程池的状态。

workerCountOf用来计算线程池中工作线程的数量。

ctlOf用来计算ctl的值。

本期的Java线程池基础介绍到这,我是shysh95,我们下期再见!

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-04-11,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 程序员修炼笔记 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
NAT 网关
NAT 网关(NAT Gateway)提供 IP 地址转换服务,为腾讯云内资源提供高性能的 Internet 访问服务。通过 NAT 网关,在腾讯云上的资源可以更安全的访问 Internet,保护私有网络信息不直接暴露公网;您也可以通过 NAT 网关实现海量的公网访问,最大支持1000万以上的并发连接数;NAT 网关还支持 IP 级流量管控,可实时查看流量数据,帮助您快速定位异常流量,排查网络故障。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档