Executors:为什么阿里不待见我?
大家好,我是Excutors,一个老实的工具类。
有个叫老三的程序员在文章 要是以前有人这么讲线程池,我早就该明白了!里挖了一个坑,说要把我介绍给大家认识认识。
我其实挺委屈的,作为一个没得感情,老实干活的工具类,我却上了阿里巴巴的黑名单。他们在一本叫《Java开发手册》的册子里写道:

作者画外音:人家为啥给你拉黑,不写的清清楚楚嘛,你有啥可委屈的。而且你这个家伙就是表面看起来老实,活是你干的吗?干活的不都是小老弟ThreadPoolExecutor。来,我一个个给你数。
1. newFixedThreadPool
FixedThreadPool,是一个固定大小的线程池。
看一下它的源代码实现:
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
直接调用ThreadPoolExecutor的构造方法。
核心线程数和最大线程数相同- 使用
LinkedBlockingQueue作为任务队列
FixedThreadPool的execute()运行示意图:

整体运行过程:
- 当前运行线程少于
corePoolSize,则创建新线程执行任务 - 当前运行线程大于
corePoolSize,将任务加入LinkedBlockingQueue - 线程池中线程执行完任务后,会循环从
LinkedBlockingQueue中获取任务执行
因为使用无界队列LinkedBlockingQueue来存储不能执行的任务,所以不会触发拒绝服务策略,可能会导致OOM。
2. newSingleThreadExecutor
SingleThreadExecutor是使用单个线程工作的线程池。
实现源码如下:
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
直接调用ThreadPoolExecutor的构造方法。
核心线程数和最大线程数都是1- 使用
LinkedBlockingQueue作为任务队列
SingleThreadExecutor的运行流程:

- 当前无运行线程,创建一个线程来执行任务
- 当前有线程运行,将任务加入
LinkedBlockingQueue - 线程执行完任务后,会循环从
LinkedBlockingQueue中获取任务来执行
这里用了无界队列LinkedBlockingQueue,同样可能会导致OOM。
3. newCachedThreadPool
CachedThreadPool是一个会根据需要创建新线程的线程池。
实现源码:
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
直接调用ThreadPoolExecutor的构造方法。
核心线程数为0,最大线程数是非常大的一个数字Integer.MAX_VALUE- 使用没有容量的
SynchronousQueue作为工作队列 keepAliveTime设置为60L,空闲线程空闲60秒之后就会被终止
CachedThreadPool的运行流程:

- 如果当前有空闲线程,使用空闲线程来执行任务
- 如果没有空闲线程,创建一个新线程来执行任务
- 新建的线程执行完任务后,会执行
poll(keepAliveTime,TimeUnit.NANOSECONDS),在SynchronousQueue里等待60s
这里线程池的大小没有限制,可能会无限创建线程,导致OOM。
4. newScheduledThreadPool
ScheduledThreadPool是一个具备调度功能的线程池。
实现源码:
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
return new ScheduledThreadPoolExecutor(corePoolSize);
}
可以看到,这个线程池不太一样,它调用的是ScheduledThreadPoolExecutor的构造方法。
public ScheduledThreadPoolExecutor(int corePoolSize) {
super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
new DelayedWorkQueue());
}
- 最大线程数是
Integer.MAX_VALUE,无限大 - 使用
DelayedWorkQueue作为任务队列
ScheduledThreadPoolExecutor执行任务的流程:

主要分为两大部分:
- 调用
scheduleAtFixedRate()/scheduleWithFixedDelay()方法,会向DelayQueue添加一个ScheduledFutureTask。 - 线程池的线程从
DelayQueue中获取ScheduledFutureTask,然后执行任务。
它同样可以无限创建线程,所以也存在OOM的风险。
为了实现周期性执行任务,ScheduledThreadPoolExecutor对ThreadPoolExecutor进行了一些改造[4]:
ScheduledFutureTask来作为调度任务的实现它主要包含了3个成员变量
time(任务将要被执行的具体时间)、sequenceNumber(任务的序号)、period(任务执行的间隔周期)使用
DelayQueue作为任务队列DelayQueue封装了了一个PriorityQueue,会对对队列中的ScheduledFutureTask进行排序,排序的优先级time>sequenceNumber。

ScheduledThreadPoolExecutor的任务执行主要分为4步:
- 线程池里的
线程1从DelayQueue中获取已到期的ScheduledFutureTask(DelayQueue.take()) 线程1执行这个ScheduledFutureTask线程1修改ScheduledFutureTask的time变量为下次将要被执行的时间。线程1把这个修改time之后的ScheduledFutureTask放回DelayQueue中(DelayQueue.add())
Excutors自述:这,这……工具类出的问题不叫bug。虽然我偷懒不干活,还可能会OOM,但我还是一个好工具类,呜呜……
作者:是啊,其实Excutors有什么错呢?它只是一个没得感情的工具类,有错的只是不恰当地用它的人。所以,知其然且知其所以然,搞懂原理,灵活应用。我们应该像一个士兵一样,不只是会扣动扳机,还会拆解保养枪械。
我是三分恶,一个号称能文能武的全栈开发。
点赞、关注不迷路,咱们下期见!
参考:
[1]. 《Java并发编程的艺术》
[2]. 讲真 这次绝对让你轻松学习线程池
[3]. 小傅哥 《Java面经手册》
[4]. 《Java并发编程之美》
[5]. 阿里巴巴《Java开发手册》
Executors:为什么阿里不待见我?的更多相关文章
- 附001.Docker阿里云Registry加速器配置
一 安装配置docker 1.1 安装docker 见<002.docker版本及安装>. 1.2 配置国内阿里云加速器 见<002.docker版本及安装>. 二 配置阿里云 ...
- J.U.C体系进阶(一):juc-executors 执行器框架
Java - J.U.C体系进阶 作者:Kerwin 邮箱:806857264@qq.com 说到做到,就是我的忍道! 主要内容: juc-executors 执行器框架 juc-locks 锁框架 ...
- java线程池,阿里为什么不允许使用Executors?
带着问题 阿里Java代码规范为什么不允许使用Executors快速创建线程池? 下面的代码输出是什么? ThreadPoolExecutor executor = new ThreadPoolExe ...
- 阿里不允许使用 Executors 创建线程池!那怎么使用,怎么监控?
作者:小傅哥 博客:https://bugstack.cn 沉淀.分享.成长,让自己和他人都能有所收获! 一.前言 五常大米好吃! 哈哈哈,是不你总买五常大米,其实五常和榆树是挨着的,榆树大米也好吃, ...
- 阿里技术专家十五问,真题面试刀刀见肉,快来和阿里面试官battle
引言 2020阿里巴巴专家组出题,等你来答: 题目:如何判断两个链表是否相交 出题人:阿里巴巴新零售技术质量部 参考答案: $O(n^2)$: 两层遍历,总能发现是否相交 $O(n)$: 一层遍历,遍 ...
- 阿里Java开发手冊之编程规约
对于程序猿来说,编程规范能够养成良好的编程习惯,提高代码质量,减少沟通成本.就在2月9号,阿里出了一份Java开发手冊(正式版),分为编程规约.异常日志.MySQL规约,project规约.安全规约五 ...
- 我的阿里之路+Java面经考点
我的阿里之路+Java面经考点 时间:2018-03-19 23:03 来源:未知 作者:admin 点击:87次 我的2017是忙碌的一年,从年初备战实习春招,年三十都在死磕JDK源码,三 ...
- [源码阅读] 阿里SOFA服务注册中心MetaServer(2)
[源码阅读] 阿里SOFA服务注册中心MetaServer(2) 目录 [源码阅读] 阿里SOFA服务注册中心MetaServer(2) 0x00 摘要 0x01 MetaServer 注册 1.1 ...
- JUC知识点总结(知识点见内部目录)
目录 JUC是什么 锁 Synchronized VS Lock 实现差异 Synchronized & Lock 总结 Synchronized锁的对象是什么 生产者&消费者 只有两 ...
随机推荐
- mumu模拟器使用
连接mumu模拟器 启动mumu模拟器 执行命令:adb connect 127.0.0.1:7555(windows系统推荐使用gitbash) 安装app Gitbash下执行:adb insta ...
- AVS 端能力之蓝牙模块
该类为蓝牙端能力处理类,主要负责蓝牙设备配对和蓝牙音频播放功能. 功能简介 实现蓝牙设备的启动发现模式.扫描蓝牙设备.建立蓝牙连接功能 实现蓝牙设备音频播放.停止.上一首.下一首功能 其它细节参考&l ...
- 解决samba和SELINUX 冲突
在使用Samba进行建立Window与Linux共享时,要是不能访问,出现"您可能没有权限使用网络资源", 那就是SELinux在作怪了 要是想让共享目录能访问,可以使用命令 #s ...
- docker run 参数
一.格式 docker run [OPTIONS] IMAGE [COMMAND] [ARG...] 二.OPTIONS 参数 简写, 名称参数 默认参数 描述 --add-host 添加自定义主机到 ...
- appium启动ios系统上面的app需求的参数
Appium启动APP至少需要7个参数 'platformVersion','deviceName'.'udid'.'bundleId'.'platformName'.'automationName ...
- Java(28)集合三Map
作者:季沐测试笔记 原文地址:https://www.cnblogs.com/testero/p/15228436.html 博客主页:https://www.cnblogs.com/testero ...
- 初学python-day4 字典(已更新完)
- Servlet学习一(Servlet的使用流程)
一.servlet运行流程 运行流程:浏览器发送请求到服务器,服务器根据url地址在webapps中寻找对应的项目文件夹然后再web.xml中检索对应的servlet,并进行调用二.servlet类写 ...
- linux下命令拼接
前言:我个five,一道特别简单的拼接题没有做出来,我吐了,不过也是涨知识了 直接切入正题了 linux命令是可以拼接的,也就是说在一个system("???")下我们的???可以 ...
- 2021.8.17考试总结[NOIP42]
$\huge{取模不能比大小!}$ $\huge{取模不能比大小!}$ $\huge{取模不能比大小!}$ 有了打地鼠的前车之鉴,我深信树规板子是可以出现在联赛题里的. 所以T1十分钟码完直接溜了,后 ...