ScheduledExecutorService:多线程任务调度

今天使用Timer实现任务调度时,阿里巴巴Java开发规范提示

  • 多线程并行处理定时任务时,Timer运行多个TimeTask时,只要其中之一没有捕获抛出的异常,其它任务便会自动终止运行,使用ScheduledExecutorService则没有这个问题。 
  • 建议多线程-任务调度,使用如下方式:
  • 首先引入commons.lang3的jar包
    <!-- https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 -->
    <dependency>
       <groupId>org.apache.commons</groupId>
        <artifactId>commons-lang3</artifactId>
        <version>3.4</version>
    </dependency>
    //org.apache.commons.lang3.concurrent.BasicThreadFactory
    ScheduledExecutorService executorService = new ScheduledThreadPoolExecutor(1,
        new BasicThreadFactory.Builder().namingPattern("example-schedule-pool-%d").daemon(true).build());
    executorService.scheduleAtFixedRate(new Runnable() {
        @Override
        public void run() {
            //do something
        }
    },initialDelay,period, TimeUnit.HOURS);
       
        
 

 

具体原因:

  1. Timer不支持多线程。全部挂在Timer下的任务都是单线程的,任务仅仅能串行运行。假设当中一个任务运行时间过长。会影响到其它任务的运行,然后就可能会有各种接踵而来的问题。
  2. Timer的线程不捕获异常。TimerTask假设抛出异常,那么Timer唯一的进程就会挂掉,这样挂在Timer下的全部任务都会无法继续运行。
  • 第一个问题,随着业务数据的猛增,我们生产上有几个任务如今每次运行须要1-3个小时。在这段时间内,该timer下的其它任务仅仅能等待,这是让人无法忍受的。重开一个Timer?难道要为全部的耗时的Task都单开一个Timer。显然是不太可能。这样就太乱了。

  • 第二个问题。是极其致命的。

  • 好多业务数据都是晚上的定时任务跑出来的。结果因为程序的问题或者内存资源不足,导致线程被kill了。该timer下的全部任务都未运行。结果第二天整整忙活了一天,主要任务就是——跑任务,调整数据。深受其害呀!

  • 为了弥补Timer的缺陷,jdk1.5中引入了并发包。这里面提供的ScheduledExecutorService。详细实现类是:ScheduledThreadPoolExecutor。ScheduledThreadPoolExecutor支持多线程。同一时候在线程中对异常进行了捕获。所以是Timer的完美替换者。

ScheduledExecutorService方法讲解

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

用来创建延迟指定时间后执行某个任务的操作,一次性执行任务,执行完成后结束。

command:等待被执行的任务 

delay:任务执行延迟时间

unit:时间单位


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

创建并执行在给定延迟后启用的 ScheduledFuture。

callable:等待被执行的任务 (这个任务,有返回值并且可以抛出异常)

delay:任务执行延迟时间

unit:时间单位

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

用来创建并执行一个延迟指定初始化时间的任务操作,周期性执行;在initialDelay后首次执行,然后initialDelay+period,initialDelay+2*period,以此类推。如果任务执行的时间小于period,则按照上面的规则执行任务,反之,任务顺延,以任务实际执行的时间来进行周期执行。

command:等待被执行的任务

initialDelay:任务初始延迟执行时间

period:任务执行间隔周期

unit:时间单位

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

用来创建并执行一个延迟指定初始化时间的任务操作,周期性执行;在initialDelay后首次执行,然后每一次执行终止和下一次的任务执行开始之间都存在delay的时间延迟,如果任务的执行时间超过延迟时间delay,则下一个任务会在任务执行时间+delay后执行

command:等待被执行的任务

initialDelay:任务初始延迟执行时间

delay:延迟时间

unit:时间单位

scheduleAtFixedRate和scheduleWithFixedDelay对比

  • 方法参数是一样的。第一个参数是任务实例,第二个参数是延迟时间,第三个是间隔时间,第四个是时间单元。
  • 这两个方法的不同之处在方法名也能看得出来:scheduleAtFixedRate方法是按照固定频率去执行任务的。而scheduleWithFixedDelay方法则是按照固定的延迟去执行任务。
  • ScheduleAtFixedRate每次执行时间为上一次任务开始起向后推一个时间间隔,即每次执行时间为initialDelay,initialDelay+period,initialDelay+2*period。。。。。
  • ScheduleWithFixedDelay每次执行时间为上一次任务结束起向后推一个时间间隔,即每次执行时间为:initialDelay,initialDelay+executeTime+delay,initialDelay+2*executeTime+2*delay。。。。。
  • 由此可见,ScheduleAtFixedRate是基于固定时间间隔进行任务调度,ScheduleWithFixedDelay取决于每次任务执行的时间长短,是基于不固定时间间隔进行任务调度。

参考来源:https://www.cnblogs.com/jzssuanfa/p/6958957.html

猜你喜欢

转载自blog.csdn.net/fly910905/article/details/81542655