Java并发编程 专题
专题目录
您的位置:java > Java并发编程专题 > ScheduledThreadPoolExecutor
ScheduledThreadPoolExecutor
作者:--    发布时间:2019-11-22

  ScheduledThreadPoolExecutorThreadPoolExecutor的子类,同时实现了ScheduledExecutorService接口,它可另行安排在给定的延迟后运行任务(Callable,Runnable),或者定期执行命令。此类要优于 Timer

   虽然此类继承自 ThreadPoolExecutor,但是几个继承的调整方法对此类并无作用。特别是,因为它作为一个使用 corePoolSize 线程和一个无界队列的固定大小的池,所以调整 maximumPoolSize 没有什么效果。

   Image.png

可以看到ScheduledThreadPoolExecutor实现了ScheduledExecutorService接口,延迟或者定时执行某个任务的方法,都定义在这个接口中

public interface ScheduledExecutorService extends ExecutorService {
//延迟指定时间来执行某个任务
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);
}

  注意,这几个方法返回的都是ScheduledFuture接口,其是Future的子接口,其只有一个实现:ScheduledFutureTask,ScheduledFutureTask同时也扩展了FutureTask,(这与我们之前讲解支持异步监听类似,当我们希望Future具备更加强大的能力时,则需要进行相应的扩展)

Image.png

  ScheduledThreadPoolExecutor重写了 AbstractExecutorService submit 方法,以生成内部ScheduledFutureTask 对象控制每个任务的延迟和调度。这个和我们在上一节的案例中,扩展ThreadPoolExecutor以支持异步监听类似,只不过上一节我们是覆盖newTaskFor方法,回顾newTaskFor就是在submit方法中调用的,相关代码片段如下:

public abstract class AbstractExecutorService implements ExecutorService {
...
public <T> Future<T> submit(Callable<T> task) {
    if (task == null) throw new NullPointerException();
    RunnableFuture<T> ftask = newTaskFor(task);
    execute(ftask);//构造之后,立即执行
    return ftask;
}
protected <T> RunnableFuture<T> newTaskFor(Callable<T> callable) {
    return new FutureTask<T>(callable);
}
...
}

  在ScheduledThreadPoolExecutor中之所以选择直接覆盖submit方法而不是newTaskFor方法,因为AbstractExecutorService中调用完成newTaskFor方法之后就立即执行了(调用execute),我们这里要实现的是延迟,或者定时执行某个任务,不能立即执行,所以选择覆盖submit方法,进行完全重写。

   

接下来,我们看看ScheduledThreadPoolExecutor如何使用,之后再分析器源码

ExecutorsE类提供了4个工厂方法,可以帮助我们快速的创建ScheduledThreadPoolExecutor

Image.png

指定延迟时间执行:

public <V> ScheduledFuture<V> schedule(Callable<V> callable,long delay,TimeUnit unit)

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

这两个方法的作用相同,只是参数类型不同,都是给定延迟时间执行某个任务,任务只会被执行一次

//任务提交时间,延迟10秒执行
public static void testSchedule(){
    System.out.println("Submit Time = "+new Date().toLocaleString());
    scheduledThreadPool.schedule(new Runnable() {
        @Override
        public void run() {
            System.out.println("ScheduledTask.run-------"+new Date().toLocaleString());
        }
    }, 10, TimeUnit.SECONDS);
}

考虑任务执行时间

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

//延迟10秒执行,之后每2秒执行一次
public static void scheduleAtFixedRate(){
    System.out.println("Submit Time = "+new Date().toLocaleString());
    scheduledThreadPool.scheduleAtFixedRate(new Runnable() {
        @Override
        public void run() {
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("ScheduledTask.run-------"+new Date().toLocaleString());
        }
    }, 10, 2,TimeUnit.SECONDS);
}

自动校正任务的执行时间,也就是说,如果任务执行了1秒,那么再过1秒就会执行,如果任务执行了1. 5秒,那么再过0. 5秒就会执行

  Submit Time = 2017-1-15 22:48:17

ScheduledTask.run-------2017-1-15 22:48:28

ScheduledTask.run-------2017-1-15 22:48:30

ScheduledTask.run-------2017-1-15 22:48:32

scheduleWithFixedDelay:不考虑任务执行时间 ,总是在上一次任务执行完成之后,再延迟指定时间进行执行

//延迟10秒执行,之后每2秒执行一次
public static void scheduleWithFixedDelay(){
    System.out.println("Submit Time = "+new Date().toLocaleString());
    scheduledThreadPool.scheduleWithFixedDelay(new Runnable() {
        @Override
        public void run() {
            try {
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("ScheduledTask.run-------"+new Date().toLocaleString());
        }
    }, 10, 2,TimeUnit.SECONDS);
}

输出

Submit Time = 2017-1-15 22:50:44

ScheduledTask.run-------2017-1-15 22:50:55

ScheduledTask.run-------2017-1-15 22:50:58

ScheduledTask.run-------2017-1-15 22:51:01

ScheduledTask.run-------2017-1-15 22:51:04


网站声明:
本站部分内容来自网络,如您发现本站内容
侵害到您的利益,请联系本站管理员处理。
联系站长
373515719@qq.com
关于本站:
编程参考手册