zoukankan      html  css  js  c++  java
  • ScheduledThreadPoolExecutor 使用线程池执行定时任务

    在现实世界里,我们总是免不了要定期去做一件事情(比如上课)—— 在计算机的世界里,更是如此。比如我们手机每天叫我们起床的电子闹钟,某些网站会定期向我们发送一些推荐相关的邮件,集群中我们需要每隔一定时间检查是否有机器宕机等。

    在 使用线程池 中已经介绍,JDK 1.5 时,标准类库添加了对线程池的支持,然后在线程池核心实现 ThreadPoolExecutor 的基础上,实现了 ScheduledThreadPoolExecutor,作为可以 定时和周期性执行任务 的线程池。ScheduledThreadPoolExecutor 的类图如下:
    ScheduledThreadPoolExecutor 的类图

    ScheduledThreadPoolExecutor 实现了 ScheduledExecutorService 接口,ScheduledExecutorService 继承了 ExecutorService 接口,所以首先 ScheduledThreadPoolExecutor 是一个 ExecutorService (线程池),然后除了具有线程池的功能,它还有定时和周期性执行任务的功能。ScheduledExecutorService 除了从 ExecutorService 继承的方法外,还包括如下四个方法:
    ScheduledExecutorService 定义的四个方法

    第一个 Schedule 方法:
    Schedule 方法

    delay 指定的时间后,执行指定的 Runnable 任务,可以通过返回的 ScheduledFuture<?> 与该任务进行交互。

    第二个 Schedule 方法:
    第二个 Schedule 方法

    delay 指定的时间后,执行指定的 Callable 任务,可以通过返回的 ScheduledFuture 与该任务进行交互。

    (ScheduledFuture 接口 继承自 Future 接口,所以 ScheduledFuture 和任务的交互方式与 Future 一致。所以通过ScheduledFuture,可以 判断定时任务是否已经完成,获得定时任务的返回值,或者取消任务等)

    scheduleAtFixedRate 方法:
    scheduleAtFixedRate 方法

    initialDelay 指定的时间后,开始按周期 period 执行指定的 Runnable 任务。
    假设调用该方法后的时间点为 0,那么第一次执行任务的时间点为 initialDelay,第二次为 initialDelay + period,第三次为 initialDelay + period + period,以此类推。

    scheduleWithFixedDelay 方法:
    scheduleWithFixedDelay 方法

    initialDelay 指定的时间后,开始按指定的 delay 延期性的执行指定的 Runnable 任务。
    假设调用该方法后的时间点为 0,每次任务需要耗时 T(i)(i 为第几次执行任务),那么第一次执行任务的时间点为 initialDelay,第一次完成任务的时间点为 initialDelay + T(1),则第二次执行任务的时间点为 initialDelay + T(1) + delay;第二次完成任务的时间点为 initialDelay + (T(1) + delay) + T(2),所以第三次执行任务的时间点为 initialDelay + T(1) + delay + T(2) + delay,以此类推。

    我们来实践下 ScheduledThreadPoolExecutor 的 scheduleAtFixedRate 方法:

    复制代码
    1 public class ScheduledExecutorServiceTest {
    2
    3 public static void main(String[] args) throws Exception {
    4 ScheduledExecutorService timer = Executors.newSingleThreadScheduledExecutor();
    5
    6 TimerTask timerTask = new TimerTask(2000); // 任务需要 2000 ms 才能执行完毕
    7
    8 System.out.printf("起始时间:%s ", new SimpleDateFormat("HH:mm:ss").format(new Date()));
    9
    10 // 延时 1 秒后,按 3 秒的周期执行任务
    11 timer.scheduleAtFixedRate(timerTask, 1000, 3000, TimeUnit.MILLISECONDS);
    12 }
    13
    14 private static class TimerTask implements Runnable {
    15
    16 private final int sleepTime;
    17 private final SimpleDateFormat dateFormat;
    18
    19 public TimerTask(int sleepTime) {
    20 this.sleepTime = sleepTime;
    21 dateFormat = new SimpleDateFormat("HH:mm:ss");
    22 }
    23
    24 @Override
    25 public void run() {
    26 System.out.println("任务开始,当前时间:" + dateFormat.format(new Date()));
    27
    28 try {
    29 System.out.println("模拟任务运行...");
    30 Thread.sleep(sleepTime);
    31 } catch (InterruptedException ex) {
    32 ex.printStackTrace(System.err);
    33 }
    34
    35 System.out.println("任务结束,当前时间:" + dateFormat.format(new Date()));
    36 System.out.println();
    37 }
    38
    39 }
    40 }
    复制代码
    运行结果:运行结果

    可以看到运行结果完全符合预期 —— 延时 1 秒后,每隔 3 秒执行一次任务。

    上面是任务的运行时间小于周期时间的情况 —— 那如果任务运行的时间大于给定的执行周期呢?(比如任务运行需要 3 s,但是我们指定的周期为 2 s)

    修改 main 方法:

    复制代码
    1 public static void main(String[] args) throws Exception {
    2 ScheduledExecutorService timer = Executors.newScheduledThreadPool(2);
    3
    4 TimerTask timerTask = new TimerTask(3000); // 每个任务需要 3000 ms 才能执行完毕
    5
    6 System.out.printf("起始时间:%s ", new SimpleDateFormat("HH:mm:ss").format(new Date()));
    7
    8 timer.scheduleAtFixedRate(timerTask, 1000, 2000, TimeUnit.MILLISECONDS);
    9 }
    复制代码
    运行结果:

    可以看到此时虽然我们指定的周期为 2 s,但是因为任务的运行就需要 3 s(超过周期),所以这种情况下 scheduleAtFixedRate 的处理方式为 上一次任务刚完成,则紧接着立即运行下一次任务,而不是使用线程池中的空闲线程来运行任务以维护 2 秒这个周期 —— 由此可见,每个定时任务在 ScheduledThreadPoolExecutor 中,都是串行运行的,即下一次运行任务一定在上一次任务结束之后。

    (scheduleWithFixedDelay 方法 的使用也十分简单,请有兴趣的读者自己实践)

  • 相关阅读:
    ios UIWebView截获html并修改便签内容(转载)
    IOS获取系统时间 NSDate
    ios 把毫秒值转换成日期 NSDate
    iOS  如何判断当前网络连接状态  网络是否正常  网络是否可用
    IOS开发 xcode报错之has been modified since the precompiled header was built
    iOS系统下 的手机屏幕尺寸 分辨率 及系统版本 总结
    iOS 切图使用 分辨率 使用 相关总结
    整合最优雅SSM框架:SpringMVC + Spring + MyBatis 基础
    Java面试之PO,VO,TO,QO,BO
    Notes模板说明
  • 原文地址:https://www.cnblogs.com/liufei5200/p/14102621.html
Copyright © 2011-2022 走看看