定时器——ScheduleThreadPoolExecutor的使用

162 阅读2分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第5天,点击查看活动详情

ScheduleThreadPoolExecutor使用

基于多线程、JVM时间实现延时、定期任务执行类。于JDK1.5版本开始提供ScheduleThreadPoolExecutor类,继承自ThreadPoolExecutor类重用线程池实现了任务的周期性调度功能。功能和Timer类似,但是提供的功能更强大、更灵活。

类型

  • ScheduledThreadPoolExecutor:执行并行任务也就是多条线程同时执行。
  • SingleThreadScheduledExecutor:执行单条线程。

使用

//一定延时后执行一次性任务
public ScheduledFuture<?> schedule(Runnable command,
                                       long delay, TimeUnit unit);
public <V> ScheduledFuture<V> schedule(Callable<V> callable,
                                           long delay, TimeUnit unit);
//一定延时后周期性执行某个任务
//间隔是固定的,无论上一个任务是否执行完成
public ScheduledFuture<?> scheduleAtFixedRate(Runnable command,
                                              long initialDelay,
                                              long period,
                                              TimeUnit unit);

//间隔是不固定的,其会在周期任务的上一个任务执行完成后才开始计时,并在指定时间间隔才可以执行任务
public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command,
                                                 long initialDelay,
                                                 long delay,
                                                 TimeUnit unit);
public static void main(String[] args) {
    //指定核心线程数, Executors.newSingleThreadScheduledExecutor(),相当于corePoolSize = 1
    ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(10);
    MyTask task1 = new MyTask("一次测试");
    MyTask task2 = new MyTask("周期测试");
    MyTask task3 = new MyTask("延迟测试");
    long delay = 0L;
    long period = 1000L;


    scheduledThreadPool.schedule(task1, delay, TimeUnit.MILLISECONDS);
    scheduledThreadPool.scheduleAtFixedRate(task2, delay, period, TimeUnit.MILLISECONDS);
    scheduledThreadPool.scheduleWithFixedDelay(task3, delay, period, TimeUnit.MILLISECONDS);
}


static class MyTask implements Runnable {
    private String taskName;

    public MyTask(String taskName) {
        this.taskName = taskName;
    }

    @Override
    public void run() {
        try {
            Thread.sleep(2000L);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        System.out.println(taskName + "执行时间:" + new Date() + "------------"
                           + "线程:" + Thread.currentThread().getName());
    }
}

从结果可以看出执行的时候使用了是不同的线程来执行。

  • schedule():延时一定时间后执行一次,后续不在继续执行
  • scheduleAtFixedRate():这个方法的作用是周期性的调度task执行。第一次执行的延迟根据initialDelay参数确定,以后每一次执行都间隔period时长。如果task的执行时间大于定义的period ,那么下一个线程将在当前线程完成之后再执行。整个调度保证不会出现一个以上任务同时执行。 所以我们可以发现上面“周期测试”并不是按照1秒间隔来执行,而是2秒。
  • scheduleWithFixedDelay():这个方法的作用也是周期性的调度,period指的当前任务的结束执行时间到下个任务的开始执行时间。 所以我们发现上面“延迟测试” 并不是按照1秒执行,而是3秒。

假如我们使用完ScheduledExecutorService需要关闭,如果不关闭, JVM会一直运行,即使所有线程都关闭了。关闭可以使用shutdown() shutdownNow() 两个方法。