JDK中线程池参详细解析
在jdk中为我们提供了三种创建线程池的方式,但是在阿里的编码规范里面都是明确禁止使用这三种api去创建线程池,推荐我们去自定义线程池。为什么?
要回答为什么,我们需要明白创建线程池时,各参数的作用:
首先我们来看一下jdk提供的创建线程池的三个api:
1. newFixedThreadPool 创建固定数量线程的线程池。
2. newSingleThreadExecutor 创建单线程的线程池
3. newCachedThreadPool 创建一个带有缓存的线程池
发现这几种创建线程池的api,实质上都是依赖于ThreadPoolExecutor类来创建线程池。
那我们来看一下ThreadPoolExecutor 创建线程池时需要的参数,以及其作用。
创建一个线程池,需要7个参数。
1. corePoolSize: 线程池的核心线程数量。初始是不创建线程的。当有任务提交到线程池时,判定如果已经创建的线程数量小于核心数量,且没有空闲线程时,则会新建一个线程去执行新提交的任务。如果已经达到核心线程数量, 则会加入到阻塞队列中。
2.maximumPoolSize: 线程池的最大容量。当线程池的阻塞队列放满了, 并且线程数量还未达到线程池的最大线程数量, 则会创建新的线程,直到达到最大值
3.keepAliveTime 当阻塞队列里面的任务被执行完了, 且有空闲线程时,指定大于核心线程池数量的部分空闲线程的存活时间, 毕竟线程也是需要消耗资源的,及时回收很有必要。当线程空闲的时间超过这个时间后,会回收掉一部分空闲线程,使其线程池中的线程数量不大于核心线程的数量
4.unit 和keepAliveTIme 配套使用,上面指定了时间的数值,但是没有指定时间的单位(时,分,秒等), 这里需要指定时间的单位
5.workQueue 阻塞队列,当没有空闲线程时,多余的任务缓存的地方。
6.threadFactory 线程工厂,用来创建线程时,设定线程的一些参数。通常我们为了后续查看日志方便,可以通过这个来指定我们自定义的线程池的线程名称
7.handler 当线程数量达到最大值时,且阻塞队列慢了, 后续在提交任务时,没有地方可以接受继续的提交的任务。这种情况下的一个拒绝策略。
拒绝策略jdK,提供了四种:
- // 由提交任务的线程执行任务
public static class CallerRunsPolicy implements RejectedExecutionHandler {- public CallerRunsPolicy() { }
- public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
- if (!e.isShutdown()) {
- r.run();
- }
- }
- }
// 不在接收新的任务,直接抛出异常- public static class AbortPolicy implements RejectedExecutionHandler {
- public AbortPolicy() { }
- public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
- throw new RejectedExecutionException("Task " + r.toString() +
- " rejected from " +
- e.toString());
- }
- }
- // 不接收也不抛出异常,空实现,忽略该任务
- public static class DiscardPolicy implements RejectedExecutionHandler {
- public DiscardPolicy() { }
- public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
- }
- }
- // 抛弃最老的任务,从阻塞队列中移除最早提交的任务,然后将该任务加入。
- public static class DiscardOldestPolicy implements RejectedExecutionHandler {
- public DiscardOldestPolicy() { }
- public void rejectedExecution(Runnable r, ThreadPoolExecutor e) {
- if (!e.isShutdown()) {
- e.getQueue().poll();
- e.execute(r);
- }
- }
- }
讲解完了创建线池时,各参数的作用,那么我们现在再反过来看为什么不让使用jdk提供的apI来创建线程池,而是需要我们自定义线程池。
newFixedThreadPool ,newSingleThreadExecutor 这两种api 使用的阻塞队列都是无界队列,也就是无论有多少个任务来,我们都接收。我们的内存是有限的,阻塞队列里面存储的任务是越多,也就意味着占用的内存越多,这样会导致占用大量的内存,容易引起OOM
newCachedThreadPool 而这个api 的阻塞队列容量为0,最大线程数量为Integer 的最大值。每当有一个任务提交时,阻塞队列存储不了,就会新开启一个线程,当任务比较多,则会创建大量的线程, 引起OOM.
这就是为什么我们在使用线程池时一定要自定义线程池的原因了。
JDK中线程池参详细解析的更多相关文章
- 沉淀再出发:java中线程池解析
沉淀再出发:java中线程池解析 一.前言 在多线程执行的环境之中,如果线程执行的时间短但是启动的线程又非常多,线程运转的时间基本上浪费在了创建和销毁上面,因此有没有一种方式能够让一个线程执行完自己的 ...
- Java并发编程中线程池源码分析及使用
当Java处理高并发的时候,线程数量特别的多的时候,而且每个线程都是执行很短的时间就结束了,频繁创建线程和销毁线程需要占用很多系统的资源和时间,会降低系统的工作效率. 参考http://www.cnb ...
- 多线程(七)JDK原生线程池
如同数据库连接一样,线程的创建.切换和销毁同样会耗费大量的系统资源.为了复用创建好的线程,减少频繁创建线程的次数,提高线程利用率可以引用线程池技术.使用线程池的优势有如下几点: 1.保持 ...
- [转] 引用 Java自带的线程池ThreadPoolExecutor详细介绍说明和实例应用
PS: Spring ThreadPoolTaskExecutor vs Java Executorservice cachedthreadpool 引用 [轰隆隆] 的 Java自带的线程池Thre ...
- Java 线程池(ThreadPoolExecutor)原理解析
在我们的开发中“池”的概念并不罕见,有数据库连接池.线程池.对象池.常量池等等.下面我们主要针对线程池来一步一步揭开线程池的面纱. 有关java线程技术文章还可以推荐阅读:<关于java多线程w ...
- Java中线程池,你真的会用吗?
在<深入源码分析Java线程池的实现原理>这篇文章中,我们介绍过了Java中线程池的常见用法以及基本原理. 在文中有这样一段描述: 可以通过Executors静态工厂构建线程池,但一般不建 ...
- Java中线程池,你真的会用吗?ExecutorService ThreadPoolExcutor
原文:https://www.hollischuang.com/archives/2888 在<深入源码分析Java线程池的实现原理>这篇文章中,我们介绍过了Java中线程池的常见用法以及 ...
- Java中java.util.concurrent包下的4中线程池代码示例
先来看下ThreadPool的类结构 其中红色框住的是常用的接口和类(图片来自:https://blog.csdn.net/panweiwei1994/article/details/78617117 ...
- Java 中线程池的 7 种创建方式!
在 Java 语言中,并发编程都是通过创建线程池来实现的,而线程池的创建方式也有很多种,每种线程池的创建方式都对应了不同的使用场景,总体来说线程池的创建可以分为以下两类: 通过 ThreadPoolE ...
随机推荐
- 吴裕雄--天生自然python学习笔记:Python3 模块
Python3 模块 在前面的几个章节中我们脚本上是用 python 解释器来编程,如果你从 Python 解释器退出再进入,那么你定义的所有的方法和变量就都消失了. 为此 Python 提供了一个办 ...
- Nginx笔记总结五:Nginx配置虚拟主机
upstream proxy1 { server ; } upstream proxy2 { server ; } server { listen ; server_name www1.dlab.co ...
- Floyd算法-dp问题
求结点对之间有负数的距离.限制条件:不允许有包含负权值的边组成的回路. 例子: 1.初始化 其中distance矩阵表示i,j两结点之间的距离. path矩阵,以第一行为例,表示0->0值为n表 ...
- 我的第一个Quartz代码
创建Maven项目 打开Eclipse->File->Project->Maven ->Maven Project直接下一步输入Group Id和Artifact Id , ...
- js 实现排序算法 -- 插入排序(Insertion Sort)
原文: 十大经典排序算法(动图演示) 插入排序 插入排序(Insertion-Sort)的算法描述是一种简单直观的排序算法.它的工作原理是通过构建有序序列,对于未排序数据,在已排序序列中从后向前扫描, ...
- LG承认手机业务遭到中国厂商碾压!这是输得心服口服的节奏?
近日,关于LG手机业退出中国市场的消息传的沸沸洋洋.不少相关媒体也对此事向LG北京办事处求证,得到的结果确实是手机业务退出中国市场.并且据韩媒报道,LG还将会逐渐取消高端手机业务,也就是说未来V系列和 ...
- 使用document.domain+iframe跨域实例
首先我们假设主页面地址为:http://www.js8.in/mywork/crossdomain/index.html,我们要加载的内容是位于work.2fool.cn域名下的helloworld. ...
- 关于CLOSE BY CLIENT STACK TRACE
关于CLOSE BY CLIENT STACK TRACE 程序正常运行,数据库连接可以获取,一些列操作都可以实现,可在debug信息中总会一段时间就报如下错误: java.lang.Exceptio ...
- linux find命令格式及find命令详解
本文详细介绍了linux find命令格式及find命令案例,希望对您的学习有所帮助.1.find命令的一般形式为:find pathname -options [-print -exec -ok . ...
- Python字符串编码——Unicode
ASCII码 我们知道,在计算机内部,所有的信息最终都表示为一个二进制的字符串.每一个二进制位(bit)有0和1两种状态,因此八个二进制位就可以组合出256种状态,这被称为一个字节(byte).也就是 ...