您的位置 首页 java

Java中调度线程池ScheduledThreadPoolExecutor原理探究

官方微信:动力节点Java学院

一、 前言

前面讲解过Java中 线程池 ThreadPoolExecutor原理探究,ThreadPoolExecutor是Executors中一部分功能,下面来介绍另外一部分功能也就是ScheduledThreadPoolExecutor的实现,后者是一个可以在一定延迟时候或者定时进行任务调度的线程池。

二、 类图结构

Executors其实是个工具类,里面提供了好多静态方法,根据用户选择返回不同的线程池实例。

ScheduledThreadPoolExecutor继承了ThreadPoolExecutor并实现ScheduledExecutorService接口,关于ThreadPoolExecutor的介绍可以参考:

线程池队列是DelayedWorkQueue,它是对delayqueue的优化,关于delayqueue参考:

ScheduledFutureTask是阻塞队列元素是对任务修饰。

构造函数:

//使用改造后的delayqueue. 

三、一个例子

// 任务间以固定时间间隔执行,延迟1s后开始执行任务,任务执行完毕后间隔2s再次执行,任务执行完毕后间隔2s再次执行,依次往复 

三、 源码分析

3.1 schedule(Runnable command, long delay,TimeUnit unit)方法

public ScheduledFuture<?> schedule(Runnable command, long delay, 

上面做的首先吧runnable装饰为delay队列所需要的格式的元素,然后把元素加入到阻塞队列,然后线程池线程会从阻塞队列获取超时的元素任务进行处理,下面看下队列元素如何实现的。

//r为被修饰任务,result=null,ns为当前时间加上delay时间后的ScheduledFutureTask(Runnable r, V result, long ns) { super(r, result); this.time = ns; this.period = 0; this.sequenceNumber = sequencer.getAndIncrement(); 

关于FutureTask可以参考

修饰后把当前任务修饰为了delay队列所需元素,下面看下元素的两个重要方法:

  • 过期时间计算

    //元素过期算法,装饰后时间-当前时间,就是即将过期剩余时间public long getDelay(TimeUnit unit) { return unit. convert (time - now(), TimeUnit.NANOSECONDS); 
  • 元素比较

    public int compareTo(Delayed other) { if (other == this) // compare zero ONLY if same object 

schedule(Callable<V> callable,

long delay,

TimeUnit unit)和schedule(Runnable command, long delay,TimeUnit unit)类似。

compareTo作用是在加入元素到dealy队列时候进行比较,需要调整堆让最快要过期的元素放到队首。所以无论什么时候向队列里面添加元素,队首的都是最即将过期的元素。

3.2 scheduleWithFixedDelay(Runnable command,long initialDelay,long delay,TimeUnit unit)

定时调度:相邻任务间时间固定

public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command, long initialDelay, long delay, 
我们知道任务添加到队列后,工作线程会从队列获取并移除到期的元素,然后执行run方法,所以下面看看ScheduledFutureTask的run方法如何实现定时调度的 
public void run() { //是否只执行一次 
private void setNextRunTime() { long p = period; if (p > 0) 

总结:定时调度是先从队列获取任务然后执行,然后在重新设置任务时间,在把任务放入队列实现的。

如果任务执行时间大于delay时间则等任务执行完毕后的delay时间后在次调用任务,不会同一个任务并发执行。

3.3 scheduleAtFixedRate(Runnable command,long initialDelay,long period,TimeUnit unit)

定时调度:相对起始时间点固定频率调用

public ScheduledFuture<?> scheduleAtFixedRate(Runnable command, long initialDelay, long period, 
private void setNextRunTime() { long p = period; //period=delay; 

总结:相对于上面delay,rate方式执行规则为时间为initdelday + n*period;时候启动任务,但是如果当前任务还没有执行完,要等到当前任务执行完毕后在执行一个任务。

四、 总结

调度线程池主要用于定时器或者延迟一定时间在执行任务时候使用。内部使用优化的DelayQueue来实现,由于使用队列来实现定时器,有出入队调整堆等操作,所以定时并不是非常非常精确。

转载自 并发编程网 – ifeve.com

文章来源:智云一二三科技

文章标题:Java中调度线程池ScheduledThreadPoolExecutor原理探究

文章地址:https://www.zhihuclub.com/176319.shtml

关于作者: 智云科技

热门文章

网站地图