目录

  • 1. 线程池的优势
  • 2. 线程池的状态
  • 3. 线程池的创建
  • 4. 线程池的种类
  • 5. 线程池提交任务流程
  • 6. 线程池提交任务的方式(`API`)
    • 6.1. `Runnable` 接口与 `Callable` 接口
    • 6.2. `ThreadPoolExecutor` 类中提交任务的方法

1. 线程池的优势

  • 降低系统资源消耗,通过重用已存在的线程,降低线程创建和销毁所造成的系统资源消耗
  • 提高系统响应速度,当有任务到达时,通过复用已存在的线程,任务可以不需要等待新线程的创建便能立即执行
  • 提高线程的可管理性,方便线程并发数的管控。如果线程无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,可能也会导致内存占用过多而产生 OOM
  • 提供更强大的功能,延时定时线程池

2. 线程池的状态

ThreadPoolExecutor 类中使用 int 的高 3 位来表示线程池状态

状态 value 说明
RUNNING(当线程池创建出来的初始状态) 111 能接受任务,能执行阻塞任务,能执行正在执行的任务
SHUTDOWN(调用shutdown方法) 000 不接受新任务,能执行阻塞任务 ,能执行正在执行的任务
STOP(调用shutDownNow) 001 不接受新任务,打断正在执行的任务,丢弃阻塞任务
TIDYING(中间状态) 010 任务全部执行完,活动线程也没了
TERMINATED(终结状态) 011 线程池终结

这几种状态的转换过程

  • 线程池在构造前(new 操作)是初始状态,一旦构造完成线程池就进入了执行状态 RUNNING;严格意义上讲线程池构造完成后并没有线程被立即启动,只有进行“预启动”或者接收到任务的时候才会启动线程。但是线程池是出于运行状态,随时准备接受任务来执行
  • 线程池运行中可以通过 shutdown()shutdownNow() 方法来改变运行状态;线程池 Executor 是异步的执行任务,因此任何时刻不能够直接获取提交的任务的状态。这些任务有可能已经完成,也有可能正在执行或者还在排队等待执行
    • shutdown() 是一个平缓的关闭过程,线程池停止接受新的任务,同时等待已经提交的任务执行完毕,包括那些进入队列还没有开始的任务,这时候线程池处于 SHUTDOWN 状态
    • shutdownNow() 是一个立即关闭过程,线程池停止接受新的任务,同时线程池取消所有执行的任务和已经进入队列但是还没有执行的任务,这时候线程池处于 STOP 状态
  • 一般情况下我们认为 shutdown() 或者 shutdownNow() 执行完毕,线程池就进入 TERMINATED 状态,此时线程池就结束了。其实,在 SHUTDOWNSTOPTERMINATED 状态之间还存在一个 TIDYING 状态
  • 当任务队列和线程池均为空的时候,线程池的状态由 STOPSHUTDOWN 状态进入到 TIDYING 状态
  • terminated() 方法被调用完成之后,线程池的状态由 TIDYING 进入到 TERMINATED 状态

3. 线程池的创建

阿里巴巴的 Java 开发手册规定:线程池不允许使用 Executors 去创建,而是通过 ThreadPoolExecutor 的方式,这样的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险;Executors 返回的线程池对象的弊端如下

  • FixedThreadPoolSingleThreadPool:允许的请求队列长度为 Integer.MAX_VALUE,可能会堆积大量的请求,从而导致 OOM
  • CachedThreadPoolScheduledThreadPool:允许的创建线程数量 Integer.MAX_VALUE,可能会创建大量的线程,从而导致 OOM
public ThreadPoolExecutor(int corePoolSize,int maximumPoolSize,long keepAliveTime,TimeUnit unit,// 时间单位 BlockingQueue<Runnable> workQueue,ThreadFactory threadFactory,RejectedExecutionHandler handler)
  • corePoolSize:核心线程数不能小于 0;如果此时线程池的线程数量小于核心线程数,那么线程池会新创建一个线程来执行任务,即使此时存在空闲线程也不例外

  • maximumPoolSize:最大线程数不能小于 corePoolSize;该参数会根据使用的 workQueue 任务队列的类型,决定线程池会开辟的最大线程数量

  • keepAliveTime:超过 corePoolSize 的线程的空闲时长,超过这个时间,多余的线程会被回收;空闲线程等待超时时间不能小于 0

  • workQueue:当线程任务添加的速度超过所有核心线程执行速度时,新来的来不及执行的线程任务将被存放到 workQueue 阻塞任务队列中

    • ArrayBlockingQueue:有界阻塞任务队列
    • LinkedBlockingQueue:通常作为无界阻塞任务队列,当有大量任务提交时,容易造成内存耗尽
    • SynchronousQueue:一个没有容量的阻塞队列,会将任务同步交付给工作线程
    • PriorityBlockingQueue:具有优先级的无界阻塞任务队列
  • threadFactory:线程工厂,用于创建线程,一般用默认即可

  • handler:拒绝策略,当任务太多来不及处理时,如何拒绝任务

    • AbortPolicy:丢弃任务并抛出异常,作为默认拒绝策略
    • CallerRunsPolicy:由调用线程(提交任务的线程)处理该任务
    • DiscardOldestPolicy:丢弃队列最前面的任务,然后重新提交被拒绝的任务
    • DiscardPolicy:丢弃任务,但是不抛出异常

4. 线程池的种类

  • newFixedThreadPool:创建一个固定大小的线程池
  • newCachedThreadPool:创建一个可缓存的线程池
  • newScheduledThreadPool:创建一个支持定时及周期性任务执行的线程池
  • newSingleThreadExecutor:创建一个单线程的线程池

5. 线程池提交任务流程

提交任务流程源码分析:execute() 核心提交任务方法

  • 如果此时线程池中的线程数量 < corePoolSize 时,即 corePoolSize 核心线程池未满,则创建新的线程来处理被添加的任务(即使线程池中的线程都处于空闲状态)
  • 如果此时线程池中的线程数量 >= corePoolSize 时,即 corePoolSize 核心线程池已满,会再去判断 workQueue 队列是否已满(队列添加任务成功,说明未满;反之,说明队列已满),如果队列未满,则将任务放入到 workQueue 队列中等待执行
  • workQueue 队列已满时,如果此时线程池中的线程数量 < maximumPoolSize 时,即该线程池未满,则继续创建线程来执行任务
  • 如果此时线程池中的线程数量 > maximumPoolSize 时,即该线程池已满,则通过 handler 所指定的拒绝策略来处理此任务

6. 线程池提交任务的方式(API

6.1. Runnable 接口与 Callable 接口

  • 可以向线程池提交的任务有 RunnableCallable 两种,其中,Callablejdk 1.5 时加入的接口,作为 Runnable 的一种补充,允许有返回值,允许抛出异常
@FunctionalInterface
public interface Callable<V> {V call() throws Exception;
}
  • 这里延伸一下使用 Callable 创建多线程
public class CallableFutureTest {public static void main(String[] args) throws ExecutionException, InterruptedException {FutureTask futureTask = new FutureTask(new Callable() {@Overridepublic Object call() throws Exception {System.out.println(Thread.currentThread().getName());return 200;}});// FutureTask 类实现了 Runnable 接口,用 Runnable 创建一个线程// 注意这里,这里传入 futureTask 参数,构造了一个 Threadnew Thread(futureTask).start();int result = (int) futureTask.get(); // 获取线程的最终结果System.out.println("result的结果:" + result);System.out.println("main come over");}
}
  • FutureTask 类实现了 RunnableFuture 接口,RunnableFuture 继承了 RunnableFuture 接口,因此 FutureTask 既可以作为一个 RunnableThread 执行,也可以获取到 Future 异步计算的结果
  • Futrue、Callable、Runnable、FutureTask 的关系:详情查看这里

6.2. ThreadPoolExecutor 类中提交任务的方法

  • void execute(Runnable command)
  • Future submit(Callable task)
  • Future<?> submit(Runnable task) :虽然返回 Future,但是其 get() 方法总是返回 null
  • Future submit(Runnable task, T result)

Java中的线程池回顾总结相关推荐

  1. 四十七、面试前,必须搞懂Java中的线程池ThreadPoolExecutor(上篇)

    @Author:Runsen @Date:2020/6/9 人生最重要的不是所站的位置,而是内心所朝的方向.只要我在每篇博文中写得自己体会,修炼身心:在每天的不断重复学习中,耐住寂寞,练就真功,不畏艰 ...

  2. 万字图文 | 学会Java中的线程池,这一篇也许就够了!

    来源:一枝花算不算浪漫 线程池原理思维导图.png 前言 Java中的线程池已经不是什么神秘的技术了,相信在看的读者在项目中也都有使用过.关于线程池的文章也是数不胜数,我们站在巨人的肩膀上来再次梳理一 ...

  3. JAVA中创建线程池的五种方法及比较

    之前写过JAVA中创建线程的三种方法及比较.这次来说说线程池. JAVA中创建线程池主要有两类方法,一类是通过Executors工厂类提供的方法,该类提供了4种不同的线程池可供使用.另一类是通过Thr ...

  4. 【多线程和并发】Java中的线程池的实现原理

    Java中的线程池是运用场景最多的并发框架,几乎所有需要异步或并发执行的程序都可以使用线程池. 合理使用线程池能带来三个好处: 降低资源消耗,通过重复利用已创建的线程降低线程创建和销毁造成的消耗: 提 ...

  5. 多线程线程池的实现java_如何在Java中实现线程池

    多线程线程池的实现java 线程是独立程序的执行路径. 在java中,每个线程都扩展java.lang.Thread类或实现java.lang.Runnable. 多线程是指在一个任务中同时执行两个或 ...

  6. 如何在Java中实现线程池

    线程是独立程序的执行路径. 在java中,每个线程都扩展java.lang.Thread类或实现java.lang.Runnable. 多线程是指在一个任务中同时执行两个或多个线程.在多线程中,每个任 ...

  7. java中的线程池有哪些,分别有什么作用?

    阅读完本篇文章会知道如下三点: 1.进程-线程简单介绍 2.java的线程池是什么,有哪些类型,作用分别是什么 3.使用线程池的优点 1.进程-线程的简单介绍 进程 什么是进程呢? 进程是计算机中的程 ...

  8. 深入理解java中的线程池

    线程池中各个参数的含义 corePoolSize: 核心池的大小,这个参数跟线程池的实现原理有非常大的关系.**在创建了线程池后,默认情况下,线程池中并没有任何线程,而是等待有任务到来才创建线程去执行 ...

  9. Java中的线程池如何实现,一文彻底搞懂

    前言 为什么要用线程池一键获取线程相关资料,还可获取最新java面试真题库 在 HotSpot VM 的线程模型中,Java 线程被一对一映射为内核线程. Java 在使用线程执行程序时,需要调用操作 ...

  10. 如何在JAVA中创建线程池

    ExecutorService 今天小编要分享的是关于线程池, 想必接触到并发处理的朋友都有用到线程池, 当我们访问服务器的量达到服务器一定量的时候, 比如几百万几千万,很容易造成服务器崩掉, 如果使 ...

最新文章

  1. 存储过程执行不报错,时间太快,但是执行无效
  2. 数据加密之MD5加密
  3. 服务器不重启磁盘修复,重启后数据盘不见了?别担心,只是磁盘脱机
  4. POJ2774 Long Long Message
  5. 【JavaWeb】JDBC的基本操作和事务控制+登录和转账案例
  6. 调试js 试用火狐的firebug
  7. closewin关闭无法返回上一层_紧急关闭iOS13,有史以来跳版本关闭系统
  8. 简单分析minidump
  9. 论文笔记:Securing Data With Blockchain and AI
  10. RDO方式安装Openstack Allinone问题记录
  11. 解决springboot的pom.xml文件第一行报错问题
  12. 坚持学下去!转行程序员的2020年度总结
  13. 七夕情人节教你如何告白~html+css+js制作唯美满天星3D相册(含音乐)程序员520表白必备
  14. FICO凭证错误:BKPFF$PRDCLN800在FI中达到的项目最大编号
  15. Python变量与字符串
  16. rand和srand的用法
  17. JavaScript数字运算必备库——big.js源码解析
  18. 如何把图片转换jpg格式呢?
  19. 【经验之谈】一个已婚男人分享找老婆的经验!
  20. 【体系结构系列】并行主存

热门文章

  1. 极客大学架构师训练营 性能测试 性能优化 第七次作业
  2. 易筋SpringBoot 2.1 | 第七篇:JPA访问MySQL
  3. 写jsx_使用Vue 3.0做JSX(TSX)风格的组件开发
  4. mysql单机三实例_Mysql单机多实例
  5. 创建运行时类的对象--Class.newInstance()
  6. react轮播图插件_React 基础面试题 - 和你随便聊聊 React
  7. AR引擎vuforia源码分析、中文注释(1)
  8. Moore-Penrose 广义逆
  9. 实数系的完备性的含义
  10. Android 开发 Camera2开发_3_处理预览和拍照偏暗问题