可扩展的Java线程池执行器
分享一下最近优锐课学习笔记。
Java线程池执行程序偏向于排队而不是产生新线程。从好的方面来说,我们有两种解决方法。
理想情况下,对任何线程池执行程序而言,期望如下:
- 预先创建了一组初始线程(核心线程池大小)来处理负载。
- 如果负载增加,则应创建更多线程来处理最大线程数(最大池大小)的负载。
- 如果线程数增加到“最大池大小”以外,则将任务排队。
- 如果使用了有界队列,并且队列已满,请引入一些拒绝策略。
下图描述了该过程;仅创建初始线程来处理任务(负载很低时)。

随着更多的任务进入,假设创建的线程总数小于最大池大小,则会创建更多的线程来处理负载(任务队列仍然为空)。

如果任务总数大于线程总数(初始+扩展),则任务队列开始填充:
不幸的是,Java线程池执行器(TPE)偏向于排队而不是生成新线程,即,在初始核心线程被占用之后,任务被添加到队列中,并且在队列达到其限制之后(这只会在有界队列中发生) ),则会产生额外的线程。如果队列不受限制,则完全不会产生扩展线程,如下图所示。

- 创建了初始核心线程来处理负载。
- 一旦任务数量超过核心线程数,队列就会开始填满以存储任务。
- 队列填满后,将创建扩展线程。
这是TPE中的代码,出现了问题

我们有两种解决方法:
解决方法1:调整池大小
将corePoolSize 和maximumPoolSize设置为相同的值,并将allowCoreThreadTimeOut 设置为true。
优点
- 无需编码技巧。
缺点
- 由于线程的创建和终止非常频繁,因此没有真正的线程缓存。
- 没有适当的可伸缩性。
解决方法2:覆盖要约方法
- 重写委托人TransferQueue的offer方法,并尝试将任务提供给空闲的工作线程之一。如果没有等待线程,则返回false。
- 实现自定义RejectedExecutionHandler以始终添加到队列中。
实现自定义RejectedExecutionHandler以始终添加到位数中。
优点
- TransferQueue确保不需要创建线程,并将工作直接转移到等待队列。
缺点
- 不能使用定制的拒绝处理程序,因为它用于插入要排队的任务。
解决方法#3:使用自定义队列
使用自定义队列(TransferQueue)并覆盖offer方法以执行以下操作:
- 尝试将任务直接转移到等待队列(如果有)。
- 如果以上操作失败,并且未达到最大池大小,则通过从offer方法返回false来创建扩展线程。
- 否则,将其插入队列。

优点
- TransferQueue确保不需要创建线程,并将工作直接转移到等待队列。
- 可以使用自定义拒绝处理程序。
缺点
- 队列和执行程序之间存在循环依赖关系。
解决方法4:使用自定义线程池执行程序
使用专门用于此目的的自定义线程池执行程序。它使用系统@ Facebook规模中所述的LIFO调度。
可扩展的Java线程池执行器的更多相关文章
- Netty核心概念(7)之Java线程池
1.前言 本章本来要讲解Netty的线程模型的,但是由于其是基于Java线程池设计而封装的,所以我们先详细学习一下Java中的线程池的设计.之前也说过Netty5被放弃的原因之一就是forkjoin结 ...
- Java并发编程系列-(6) Java线程池
6. 线程池 6.1 基本概念 在web开发中,服务器需要接受并处理请求,所以会为一个请求来分配一个线程来进行处理.如果每次请求都新创建一个线程的话实现起来非常简便,但是存在一个问题:如果并发的请求数 ...
- 【转载】深度解读 java 线程池设计思想及源码实现
总览 开篇来一些废话.下图是 java 线程池几个相关类的继承结构: 先简单说说这个继承结构,Executor 位于最顶层,也是最简单的,就一个 execute(Runnable runnable) ...
- Java并发指南12:深度解读 java 线程池设计思想及源码实现
深度解读 java 线程池设计思想及源码实现 转自 https://javadoop.com/2017/09/05/java-thread-pool/hmsr=toutiao.io&utm_ ...
- Java 线程池框架核心代码分析--转
原文地址:http://www.codeceo.com/article/java-thread-pool-kernal.html 前言 多线程编程中,为每个任务分配一个线程是不现实的,线程创建的开销和 ...
- (转载)JAVA线程池管理
平时的开发中线程是个少不了的东西,比如tomcat里的servlet就是线程,没有线程我们如何提供多用户访问呢?不过很多刚开始接触线程的开发攻城师却在这个上面吃了不少苦头.怎么做一套简便的线程开发模式 ...
- Java 线程池框架核心代码分析
前言 多线程编程中,为每个任务分配一个线程是不现实的,线程创建的开销和资源消耗都是很高的.线程池应运而生,成为我们管理线程的利器.Java 通过Executor接口,提供了一种标准的方法将任务的提交过 ...
- Java线程池使用和分析(一)
线程池是可以控制线程创建.释放,并通过某种策略尝试复用线程去执行任务的一种管理框架,从而实现线程资源与任务之间的一种平衡. 以下分析基于 JDK1.7 以下是本文的目录大纲: 一.线程池架构 二.Th ...
- 由浅入深理解Java线程池及线程池的如何使用
前言 多线程的异步执行方式,虽然能够最大限度发挥多核计算机的计算能力,但是如果不加控制,反而会对系统造成负担.线程本身也要占用内存空间,大量的线程会占用内存资源并且可能会导致Out of Memory ...
随机推荐
- nyoj 457-大小写互换
457-大小写互换 内存限制:64MB 时间限制:1000ms 特判: No 通过数:18 提交数:21 难度:0 题目描述: 现在给出了一个只包含大小写字母的字符串,不含空格和换行,要求 ...
- 力扣(LeetCode)单值二叉树 个人题解
如果二叉树每个节点都具有相同的值,那么该二叉树就是单值二叉树. 只有给定的树是单值二叉树时,才返回 true:否则返回 false. 示例 1: 输入:[1,1,1,1,1,null,1] 输出:tr ...
- 力扣(LeetCode)环形链表 个人题解
给定一个链表,判断链表中是否有环. 为了表示给定链表中的环,我们使用整数 pos 来表示链表尾连接到链表中的位置(索引从 0 开始). 如果 pos 是 -1,则在该链表中没有环. 示例 1: 输入: ...
- C语言|博客作业08
这个作业属于哪个课程 C语言程序设计II 这个作业的要求在哪里 https://edu.cnblogs.com/campus/zswxy/CST2019-1/homework/9976 我在这个课程的 ...
- ZeroC ICE的远程调用框架 ThreadPool
ThreadPool提供Reactor/Proactor服务,并且强偶合了Reactor(反应器)/Proactor(前摄器).不同于Reactor/Proactor使用线程池 进行事件处理的设计.如 ...
- PHP 的面向对象 与 类
面向对象 == OO 学习面向对象 == XXOO;[学习使我快乐!] <!--附一个demo类的实例化--> http://note.youdao.com/noteshare?id=38 ...
- [Part 4] 在Windows 10上源码编译PCL 1.8.1支持VTK和QT,可视化三维点云
本文首发于个人博客https://kezunlin.me/post/2d809f92/,欢迎阅读! Part-4: Compile pcl with vtk qt5 support from sour ...
- Component 和 PureComponent 的区别;复制demo,肉眼可以的区别
React.PureComponent它用当前与之前 props 和 state 的浅比较覆写了 shouldComponentUpdate() 的实现.简单来说,就是PureComponent简单实 ...
- vue中插槽的使用场景
效果图:
- 原生JS通过类名(className)获取dom元素
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...
