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);
具体原因:
- Timer不支持多线程。全部挂在Timer下的任务都是单线程的,任务仅仅能串行运行。假设当中一个任务运行时间过长。会影响到其它任务的运行,然后就可能会有各种接踵而来的问题。
- 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