java的线程池有几种 java线程的创建方式( 二 )


  1. 内存池(Memory Pooling):预先申请内存 , 提升申请内存速度 , 减少内存碎片 。
  2. 连接池(Connection Pooling):预先申请数据库连接 , 提升申请连接的速度 , 降低系统的开销 。
  3. 实例池(Object Pooling):循环使用对象 , 减少资源在初始化和释放时的昂贵损耗 。
在了解完“是什么”和“为什么”之后 , 下面我们来一起深入一下线程池的内部实现原理 。
二、线程池核心设计与实现在前文中 , 我们了解到:线程池是一种通过“池化”思想 , 帮助我们管理线程而获取并发性的工具 , 在Java中的体现是ThreadPoolExecutor类 。那么它的的详细设计与实现是什么样的呢?我们会在本章进行详细介绍 。
2.1 总体设计
Java中的线程池核心实现类是ThreadPoolExecutor , 本章基于JDK 1.8的源码来分析Java线程池的核心设计与实现 。我们首先来看一下ThreadPoolExecutor的UML类图 , 了解下ThreadPoolExecutor的继承关系 。
java的线程池有几种 java线程的创建方式


图1 ThreadPoolExecutor UML类图
ThreadPoolExecutor实现的顶层接口是Executor , 顶层接口Executor提供了一种思想:将任务提交和任务执行进行解耦 。用户无需关注如何创建线程 , 如何调度线程来执行任务 , 用户只需提供Runnable对象 , 将任务的运行逻辑提交到执行器(Executor)中 , 由Executor框架完成线程的调配和任务的执行部分 。ExecutorService接口增加了一些能力:(1)扩充执行任务的能力 , 补充可以为一个或一批异步任务生成Future的方法;(2)提供了管控线程池的方法 , 比如停止线程池的运行 。
AbstractExecutorService则是上层的抽象类 , 将执行任务的流程串联了起来 , 保证下层的实现只需关注一个执行任务的方法即可 。最下层的实现类ThreadPoolExecutor实现最复杂的运行部分 , ThreadPoolExecutor将会一方面维护自身的生命周期 , 另一方面同时管理线程和任务 , 使两者良好的结合从而执行并行任务 。
ThreadPoolExecutor是如何运行 , 如何同时维护线程和执行任务的呢?其运行机制如下图所示:
java的线程池有几种 java线程的创建方式


图2 ThreadPoolExecutor运行流程
线程池在内部实际上构建了一个生产者消费者模型 , 将线程和任务两者解耦 , 并不直接关联 , 从而良好的缓冲任务 , 复用线程 。线程池的运行主要分成两部分:任务管理、线程管理 。任务管理部分充当生产者的角色 , 当任务提交后 , 线程池会判断该任务后续的流转:(1)直接申请线程执行该任务;(2)缓冲到队列中等待线程执行;(3)拒绝该任务 。线程管理部分是消费者 , 它们被统一维护在线程池内 , 根据任务请求进行线程的分配 , 当线程执行完任务后则会继续获取新的任务去执行 , 最终当线程获取不到任务的时候 , 线程就会被回收 。
接下来 , 我们会按照以下三个部分去详细讲解线程池运行机制:
  1. 线程池如何维护自身状态 。
  2. 线程池如何管理任务 。
  3. 线程池如何管理线程 。
2.2 生命周期管理
线程池运行的状态 , 并不是用户显式设置的 , 而是伴随着线程池的运行 , 由内部来维护 。线程池内部使用一个变量维护两个值:运行状态(runState)和线程数量 (workerCount) 。在具体实现中 , 线程池将运行状态(runState)、线程数量 (workerCount)两个关键参数的维护放在了一起 , 如下代码所示:

推荐阅读