java 异步线程_Java并发编程十一 异步之线程池ScheduledThreadPoolExecutor

本文介绍了ScheduledThreadPoolExecutor类,它是Java中用于执行周期性任务的线程池。ScheduledThreadPoolExecutor继承自ThreadPoolExecutor,实现了ScheduledExecutorService接口,提供schedule、scheduleAtFixedRate和scheduleWithFixedDelay等方法来执行延迟和周期性任务。文章详细讲解了构造函数、特有方法,包括DelayedWorkQueue和ScheduledFutureTask两个内部类的工作原理,并给出了使用示例。
摘要由CSDN通过智能技术生成

上一节介绍了java线程池ThreadPoolExecutor类,这节介绍周期性线程池ScheduledThreadPoolExecutor类。

1、ScheduledThreadPoolExecutor类图

bce7a24412bcefe82f53fdfd0facd54e.png
图1-1 ScheduledThreadPoolExecutor类图

从类图可以看出ScheduledThreadPoolExecutor类继承了ThreadPoolExector类,就是说ScheduledThreadPoolExecutor拥有execute()和submit()提交异步任务的基础功能,同时实现了一个新接口:ScheduledExecutorService,ScheduledExecutorService接口继承的是ExecutorService接口,下面我们看看ScheduledExecutorService接口里有哪些方法:

b9a2a588d27a4727a25a9d110e9ee10f.png
图1-2 ScheduledExecutorService接口中的方法

其中schedule方法是用来执行线程任务的,接收Runnable类型和Callable类型的任务;scheduleAtFixRate和scheduleWithFixedDelay方法是用来执行周期性任务和周期性延迟任务的,具体在下面会介绍。

2、ScheduledThreadPoolExecutor类详细介绍

2.1 构造函数

源码如下:

public ScheduledThreadPoolExecutor(int corePoolSize) {
    super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
          new DelayedWorkQueue());
};

public ScheduledThreadPoolExecutor(int corePoolSize,
                                   ThreadFactory threadFactory) {
    super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
          new DelayedWorkQueue(), threadFactory);
};
public ScheduledThreadPoolExecutor(int corePoolSize,
                                   RejectedExecutionHandler handler) {
    super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
          new DelayedWorkQueue(), handler);
};

public ScheduledThreadPoolExecutor(int corePoolSize,
                                   ThreadFactory threadFactory,
                                   RejectedExecutionHandler handler) {
    super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
          new DelayedWorkQueue(), threadFactory, handler);
}

可以看出ScheduledThreadPoolExecutor类的构造函数都是用的父类的构造函数,即ThreadPoolExecutor类的构造函数,且传入的参数都很固定:corePoolSize、maxPoolSize(Integer.MAX_VALUE)、keepAliveTime(0),阻塞队列(DelayedWorkQueue),关于这个DelayedWorkQueue下面介绍。

初始化ScheduledThreadPoolExecutor类除了用其构造函数外,还可以使用Excutors类提供的工厂方法:

public static ScheduledExecutorService newSingleThreadScheduledExecutor() {
        return new DelegatedScheduledExecutorService
            (new ScheduledThreadPoolExecutor(1));
    }

public static ScheduledExecutorService newSingleThreadScheduledExecutor(ThreadFactory threadFactory) {
    return new DelegatedScheduledExecutorService
        (new ScheduledThreadPoolExecutor(1, threadFactory));
}

public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
    return new ScheduledThreadPoolExecutor(corePoolSize);
}


public static ScheduledExecutorService newScheduledThreadPool(
        int corePoolSize, ThreadFactory threadFactory) {
    return new ScheduledThreadPoolExecutor(corePoolSize, threadFactory);
}

提供了初始化两种类型的周期性线程池,只是初始化参数不同:

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

其底层都是用的ScheduledThreadPoolExecutor类的构造方法实现的,而ScheduledThreadPoolExecutor类的构造方法是用的ThreadPoolExecutor类的构造方法。

2.2 特有方法

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);

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

该方法是执行延迟任务,即达到给定的延迟时间:delay后才执行线程任务(仅执行一次),且接收的是实现Runnable接口的类的实例。

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

该方法也是执行延迟任务(仅执行一次),与上面方法唯一不同的是接收的线程任务的类型不同,该方法接收的是实现了Callabel接口的类的实例。

(3)ScheduledFuture<?>scheduleAtFixedRate(Runnable command,long initialDelay,long period, TimeUnit unit)

该方法是在固定延迟后,周期性的执行线程池任务,入参中initialDelay是固定延迟,超过这个时间后,线程池开始执行任务;period是执行周期,准确地说是上一次开始执行任务的时刻到下一次开始执行任务的时刻中间的时间间隔,当时间间隔大于任务执行时间时,时间间隔还是以period为准,当时间间隔小于任务执行时间时,时间间隔是以任务执行时间为准。

(4)ScheduledFuture<?>scheduleWithFixedDelay(Runnable command,long initialDelay,long delay, TimeUnit unit)

该方法是在固定延迟后,周期性延迟执行线程池任务,入参中initialDelay是固定延迟,超过这个时间后,线程池开始执行任务;delay是周期性延迟的时间,准确地说是上一次任务结束的时刻到下一次任务开始的时刻中间的时间间隔;与scheduleAtFixedRate不同的是,当delay大于或者小于任务执行时间时,延迟间隔还是按delay走,不像scheduleAtFixedRate一样周期会改变。

有关(3)和(4)的区分可以参考链接2。

2.3 两个内部类:DelayedWorkQueue和ScheduledFutureTask

1)DelayedWorkQueue

DelayedWorkQueue是ScheduledThreadPoolExecutor线程池使用的阻塞队列,DelayedWorkQueue是一个优先级队列,它可以保证每次出队的任务都是当前队列中执行时间最靠前的,具体我没仔细看...

(2)ScheduledFutureTask

ScheduledThreadPoolExecutor类的schedule方法的源码如下:

public ScheduledFuture<?> schedule(Runnable command,
                                   long delay,
                                   TimeUnit unit) {
    if (command == null || unit == null)
        throw new NullPointerException();
    RunnableScheduledFuture<?> t = decorateTask(command,
        new ScheduledFutureTask<Void>(command, null,
                                      triggerTime(delay, unit)));
    delayedExecute(t);
    return t;
}

在schedule方法里,会通过decorateTask方法将传入的Runnable类型的任务转化成ScheduledFutureTask任务,ScheduledFutureTask继承了FutureTask并实现了RunnableScheduledFuture接口,为了保证ScheduledThreadPoolExecutor能够延时执行任务以及能够周期性执行任务,ScheduledFutureTask重写了run方法,源码如下:

public void run() {
    boolean periodic = isPeriodic();
    if (!canRunInCurrentRunState(periodic))
        cancel(false);
    else if (!periodic)
        //如果不是周期性执行任务,则直接调用run方法
        ScheduledFutureTask.super.run();
        //如果是周期性执行任务的话,需要重设下一次执行任务的时间
    else if (ScheduledFutureTask.super.runAndReset()) {
        setNextRunTime();
        reExecutePeriodic(outerTask);
    }

这块我没细看。

3、使用举例

package ThreadExecutorPool;


import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.*;


/**
 * @ClassName ScheduledThreadPoolExecutorDemo
 * @Description TODO
 * @Auther Jerry
 * @Date 2020/3/24 - 23:49
 * @Version 1.0
 */

public class ScheduledThreadPoolExecutorDemo {
    public static void main(String[] args) {
        // 工厂方法初始化周期性线程池
        ScheduledExecutorService threadPool1 = Executors.newScheduledThreadPool(5);
        // 初始化延迟任务
        DelayTask delayTask = new DelayTask();

        SimpleDateFormat formatter= new SimpleDateFormat("yyyy-MM-dd 'at' HH:mm:ss z");
        Date date = new Date(System.currentTimeMillis());
        System.out.println(Thread.currentThread().getName() + "当前时刻:" + formatter.format(date));

        ScheduledFuture <Integer> result = threadPool1.schedule(delayTask, 5, TimeUnit.SECONDS);

        try {
            System.out.println(Thread.currentThread().getName() + " 执行结果:" + result.get());
        }
        catch (InterruptedException e)
        {
            e.printStackTrace();
        }
        catch (ExecutionException e)
        {
            e.printStackTrace();
        }

        // 工厂方法初始化周期性线程池
        ScheduledExecutorService threadPool2 = Executors.newSingleThreadScheduledExecutor();
        // 初始话周期性任务
        PeriodTask periodTask = new PeriodTask();

        threadPool2.scheduleAtFixedRate(periodTask, 0, 2, TimeUnit.SECONDS);
    }

    static class DelayTask implements Callable<Integer> {
        int sum = 0;

        @Override
        public Integer call() throws Exception {
            SimpleDateFormat formatter= new SimpleDateFormat("yyyy-MM-dd 'at' HH:mm:ss z");
            Date date = new Date(System.currentTimeMillis());

            System.out.println(Thread.currentThread().getName() + "延迟后开始执行任务的时刻:" + formatter.format(date));
            for (int i = 0; i < 100; ++i) {
                sum += i;
            }
            return sum;
        }
    }

    static class PeriodTask implements Runnable{
        @Override
        public void run() {
            System.out.println(Thread.currentThread().getName() + "我要离职");
        }
    }
}

执行结果如下:

main当前时刻:2020-03-27 at 00:58:41 CST
pool-1-thread-1延迟后开始执行任务的时刻:2020-03-27 at 00:58:46 CST
main 执行结果:4950
pool-2-thread-1我要离职
pool-2-thread-1我要离职
pool-2-thread-1我要离职
pool-2-thread-1我要离职
pool-2-thread-1我要离职
pool-2-thread-1我要离职
...

参考

线程池之ScheduledThreadPoolExecutor​www.jianshu.com
cac81ed8f59ce8c30e58d75480f2b89a.png
CSDN-专业IT技术社区-登录​blog.csdn.net
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值