大家好,我是Excutors
,一个老实的工具类。
有个叫老三的程序员在文章 要是以前有人这么讲线程池,我早就该明白了!里挖了一个坑,说要把我介绍给大家认识认识。
我其实挺委屈的,作为一个没得感情,老实干活的工具类,我却上了阿里巴巴的黑名单。他们在一本叫《Java开发手册》的册子里写道:
作者画外音:人家为啥给你拉黑,不写的清清楚楚嘛,你有啥可委屈的。而且你这个家伙就是表面看起来老实,活是你干的吗?干活的不都是小老弟ThreadPoolExecutor
。来,我一个个给你数。
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
。
SingleThreadExecutor
是使用单个线程工作的线程池。
实现源码如下:
public static ExecutorService newSingleThreadExecutor() {return new FinalizableDelegatedExecutorService(new ThreadPoolExecutor(1, 1,0L, TimeUnit.MILLISECONDS,new LinkedBlockingQueue<Runnable>()));}
直接调用ThreadPoolExecutor
的构造方法。
核心线程数
和最大线程数
都是1LinkedBlockingQueue
作为任务队列SingleThreadExecutor
的运行流程:
LinkedBlockingQueue
LinkedBlockingQueue
中获取任务来执行这里用了无界队列LinkedBlockingQueue
,同样可能会导致OOM
。
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
。
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开发手册》
本文发布于:2024-01-29 05:16:09,感谢您对本站的认可!
本文链接:https://www.4u4v.net/it/170647657412957.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
留言与评论(共有 0 条评论) |