ScheduledExecutorService
前言
在Java中我们一般使用Timer来进行延时/周期执行操作,Timer的内部只有一个线程,如果有多个任务的话就会顺序执行,这样我们的延迟时间和循环时间就会出现问题。除此之外:在多线程并发执行定时操作时,Timer运行多个TimerTask,如果其中一个任务没有异常没有捕获,那所有任务都将终止。还有就是,Timer是基于绝对时间,而ScheduledExecutorService是基于相对时间的,这个看情况而定,一般基于相对时间更灵活一些。所以作为Timer的替代品,在对延迟任务和循环任务要求严格的时候,最好使用ScheduledExecutorService。
ScheduledExecutorService提供了三种方法来进行延时/周期操作:schedule、scheduleAtFixedRate、scheduleWithFixedDelay。
schedule方法
ScheduledExecutorService用于延迟一段时间后执行任务或者周期性的执行任务.通常使用Executor类的工厂方法去实例化一个ScheduledExecutorService是一个比较好的方式。.
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(1000);
//延迟两秒打印fsd,这里使用了lamda表达式简化,相当于new Runable()
scheduledThreadPool.schedule(() ->System.out.println("fsd"), 2, TimeUnit.SECONDS);
scheduleAtFixedRate方法
scheduleAtFixedRate()方法在延迟一段时间之后周期性的执行一个任务.下面的代码将会先延迟1秒之后首次执行,之后每隔3秒执行,不管任务耗时多久,3秒后都立即执行下一个任务。
ScheduledExecutorService executorService =Executors.newSingleThreadScheduledExecutor();
//第一次延迟一秒打印,后每三秒打印一次,这里使用了lamda表达式简化,相当于new Runable()
executorService.scheduleAtFixedRate(() ->System.out.println("fsd"),1,3,TimeUnit.SECONDS);
总结一下就是:scheduleAtFixedRate是按照上一次任务的发起时间计算下一次任务的开始时间。
scheduleWithFixedDelay方法
如果需要任务周期性执行的时候保持固定的时间间隔,应该使用scheduleWithFixedDalay()方法.如下的代码保证上一次任务执行完(不管多久)过10秒之后再执行下一次任务.
ScheduledExecutorService executorService =Executors.newSingleThreadScheduledExecutor();
//第一次延迟一秒打印,后每三秒打印一次,这里使用了lamda表达式简化,相当于new Runable()
executorService.scheduleWithFixedDelay(() ->System.out.println("fsd"),1,3,TimeUnit.SECONDS);
总结一下就是:.scheduleWithFixedDelay以上一次任务的结束时间计算下一次任务的开始时间
**注意:
如果ExecutorService被关闭,或者在任务执行过程中抛出了一个异常,那么周期性执行的任务将会终止.。所以最好在Runable中的run方法中捕获所有异常,保证循环的进行,如下:
public class MyThread implements Runnable{
@Override
public void run() {
try {
int sleepNumber = random.nextInt(3);
if(sleepNumber ==2){
int error = 1/0;
}
} catch (Exception e) {
e.printStackTrace();
}
}
网友评论