任务调度实现

任务调度

定义:任务调度是基于给定时间点,给定时间间隔或者给定执行次数自动执行任务。

Timer

Timer 是jdk提供的一个定时器工具,会在主线程之外起一个单独线程执行指定的计划任务。

public class TimerTest extends TimerTask {

    private String jobName;

    public TimerTest(String jobName) {
        this.jobName = jobName;
    }

    @Override
    public void run() {
        System.out.println("执行:" + jobName);
    }

    public static void main(String[] args) {
        Timer timer = new Timer();
        long delay1 = 1 * 1000;
        long interval1 = 1000;

        //从现在开始1秒后每隔1秒执行一次job1
        timer.schedule(new TimerTest("job1"), delay1, interval1);

        long delay2 = 2 * 1000;
        long interval2 = 2000;
        // 从现在开始2秒钟之后,每隔2秒钟执行一次 job2
        timer.schedule(new TimerTest("job2"), delay2, interval2);

        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        //终止执行
        timer.cancel();
    }
}

Timer 的优点在于简单易用,但由于所有任务都是由同一个线程来调度,因此所有任务都是串行执行的,同一时间只能有一个任务在执行,前一个任务的延迟或异常都将会影响到之后的任务

ScheduledExecutor

ScheduledExecutor 类则在自定义线程池的基础上增加了周期性执行任务的功能

ScheduledThreadPoolExecutor 线程池中的每一个线程负责执行一个定时任务,相互之间互不干扰,并发执行,线程池会轮询任务状态,执行时间到来才会真正执行线程。

public class ScheduledExecutorTest implements Runnable {

    private String jobName;

    public ScheduledExecutorTest(String jobName) {
        this.jobName = jobName;
    }

    public void run() {
        System.out.println("Start: " + getDate());
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("execute " + jobName);
        System.out.println("End: " + getDate());
    }
    
    //获取当前时间
    public String getDate() {
        SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");//设置日期格式
        return df.format(new Date());// new Date()为获取当前系统时间
    }

    public static void main(String[] args) {
        ScheduledExecutorService service = Executors.newScheduledThreadPool(10);

        long initialDelay1 = 1;
        long period1 = 2;
        //固定时间间隔
        service.scheduleAtFixedRate(new ScheduledExecutorTest("job1"),
                initialDelay1, period1, TimeUnit.SECONDS);

        long initialDelay2 = 1;
        long peroid2 = 3;
        //本次执行结束和下次开始执行时间保持在三秒
        //每次执行时间:executeTime + peroid executeTime可能会变化,但是peroid不变
        /*service.scheduleWithFixedDelay(new ScheduledExecutorTest("job2"),
                initialDelay2, peroid2, TimeUnit.SECONDS); */
    }
}

使用Executors.newScheduledThreadPool(10)创建一个核心线程数量为10的线程池。

方法区别:
1.scheduleAtFixedRate(Runnable command, long initialDelay, long period, TimeUnit unit)
参数:

  • Runnable 需要执行的task
  • initialDelay 延迟至启动任务的时间
  • period 本次开始到下次开始的时间间隔

注:

  • 若本次job执行时间小于period,本次开始执行和下次开始之间时间间隔固定
  • 若本次job执行时间大于period,则本次开始时间和下次开始时间间隔为job执行时间
  • 每次执行时间 :executeTime < period ? peroid : executeTime
  • 不会因为上一个线程的调度失效延迟而受到影响,固定频率触发执行

2.scheduleWithFixedDelay(Runnable command, long initialDelay, long period, TimeUnit unit)
注:

  • 本次执行结束和下次开始执行时间保持在三秒
  • 每次执行时间:executeTime + peroid executeTime可能会变化,但是peroid不变
  • 受到上一个线程调度影响,可能会推迟本次任务调度的执行,固定延时触发执行
实现原理:

ScheduledThreadPool创建的线程池底层使用的是DelayQueue

Delayed元素的一个无界阻塞队列,只有在延迟期满时才能从中提取元素。该队列的头部是延迟期满后保存时间最长的Delayed元素。如果延迟都还没有期满,则队列没有头部,并且poll将返回null。

当一个元素的 getDelay(TimeUnit.NANOSECONDS)方法返回一个小于等于0的值时,将发生到期。即使无法使用take或poll移除未到期的元素,也不会将这些元素作为正常元素对待。例如,size方法同时返回到期和未到期元素的计数。此队列不允许使用null元素

ScheduledThreadPoolExecutor是把任务添加到DelayedWorkQueue中,而DelayedWorkQueue则是类似于DelayQueue,内部维护着一个以时间为先后顺序的优先级队列,使用compareTo()方法使用与DelayedWorkQueue队列对其元素ScheduledThreadPoolExecutor task进行排序

小结:

上面创建线程池建议使用ScheduledThreadPoolExecutor,可以更加精确控制。
构造函数其中一个参数为DelayedWorkQueue,内部通过一个RunnableScheduledFuture数组保存Runnable任务,默认初始长度为16,它是一个优先级队列
它根据这个任务的下次执行时间来比较大小,这样能够保证queue[0]位置上的元素是最近需要执行的任务。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值