补充部分---ScheduledThreadPoolExecutor类分析 线程池底层原理详解与源码分析

【1】前言
本篇幅是对 线程池底层原理详解与源码分析  的补充,默认你已经看完了上一篇对ThreadPoolExecutor类有了足够的了解 。
【2】ScheduledThreadPoolExecutor的介绍
1.ScheduledThreadPoolExecutor继承自ThreadPoolExecutor 。它主要用来在给定的延迟之后运行任务,或者定期执行任务 。ScheduledThreadPoolExecutor可以在构造函数中指定多个对应的后台线程数 。
2.构造函数展示
public ScheduledThreadPoolExecutor(int corePoolSize) {super(corePoolSize, Integer.MAX_VALUE,DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,new DelayedWorkQueue());}public ScheduledThreadPoolExecutor(int corePoolSize,ThreadFactory threadFactory) {super(corePoolSize, Integer.MAX_VALUE,DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,new DelayedWorkQueue(), threadFactory);}public ScheduledThreadPoolExecutor(int corePoolSize,RejectedExecutionHandler handler) {super(corePoolSize, Integer.MAX_VALUE,DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,new DelayedWorkQueue(), handler);}public ScheduledThreadPoolExecutor(int corePoolSize,ThreadFactory threadFactory,RejectedExecutionHandler handler) {super(corePoolSize, Integer.MAX_VALUE,DEFAULT_KEEPALIVE_MILLIS, MILLISECONDS,new DelayedWorkQueue(), threadFactory, handler);}【补充部分---ScheduledThreadPoolExecutor类分析 线程池底层原理详解与源码分析】3.通过构造函数我们可以看到,它的线程池本身就是调用ThreadPoolExecutor类的构造方法,因此也继承了ThreadPoolExecutor类所存在的隐患:
允许的请求队列长度为 Integer.MAX_VALUE,可能会堆积大量的请求 , 从而导致 OOM 。允许的创建线程数量为 Integer.MAX_VALUE,可能会创建大量的线程,从而导致 OOM 。(且CPU会变成100%)
4.PS:既然隐患这么严重 , 使用原生的不太合适 。正所谓,人无横财不富 , 马无夜草不肥,打不过就加入 。ScheduledThreadPoolExecutor继承自ThreadPoolExecutor,那就写个类继承它然后调用ThreadPoolExecutor的构造方法区解决掉创建线程数被写死为最大值的情况,然后了解一下DelayedWorkQueue(这个本质上也是优先级队列),继承一下也改写吧 。毕竟自己的最合适不是吗 。【毕竟我觉得这些都是大佬们留给菜鸡的底版,如拒绝策略不也是四个默认都没人用吗,都是要你根据自己的场景改】(毕竟我这猜测的原因是因为有了无尽队列 , 其实线程数设置为Integer.MAX_VALUE已经没有意义了)
【3】ScheduledThreadPoolExecutor的使用
1)schedule(Runnable command, long delay, TimeUnit unit)
方法说明:无返回值的延迟任务,有个严重的问题,就是没有办法获知task的执行结果2)schedule(Callable callable, long delay, TimeUnit unit)
方法说明:有返回值的延迟任务 :接收的是Callable实例 , 会返回一个ScheduleFuture对象,通过ScheduleFuture可以取消一个未执行的task,也可以获得这个task的执行结果3)scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit)
方法说明: 固定频率周期任务:第一次执行的延迟根据initialDelay参数确定,以后每一次执行都间隔period时长4)scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, TimeUnit unit)
方法说明: 固定延迟周期任务 :scheduleWithFixedDelay的参数和scheduleAtFixedRate参数完全一致,它们的不同之处在于对period调度周期的解释 。在scheduleAtFixedRate中 , period指的两个任务开始执行的时间间隔,也就是当前任务的开始执行时间和下个任务的开始执行时间之间的间隔 。而在scheduleWithFixedDelay中,period指的当前任务的结束执行时间到下个任务的开始执行时间 。
【4】任务ScheduledFutureTask类源码分析
1.构造方法展示
代码展示
private class ScheduledFutureTask<V> extends FutureTask<V> implements RunnableScheduledFuture<V> {...ScheduledFutureTask(Runnable r, V result, long triggerTime, long sequenceNumber) {super(r, result);this.time = triggerTime; //表示这个任务将要被执行的具体时间this.period = 0;//表示任务执行的间隔周期this.sequenceNumber = sequenceNumber;//表示这个任务被添加到ScheduledThreadPoolExecutor中的序号(采用AtomicLong原子类累加当做序号)}ScheduledFutureTask(Runnable r, V result, long triggerTime, long period, long sequenceNumber) {super(r, result);this.time = triggerTime;this.period = period;this.sequenceNumber = sequenceNumber;}ScheduledFutureTask(Callable<V> callable, long triggerTime, long sequenceNumber) {super(callable);this.time = triggerTime;this.period = 0;this.sequenceNumber = sequenceNumber;} ...}代码说明
1.三个标注的参数是任务中主要的成员变量 。
2.其次,我们会发现callable的任务是没有间隔周期的:因为callable本身就是阻塞等待,而且周期性的也不合适 。

推荐阅读