计划任务之ScheduledExecutorService
在讲ScheduledExecutorService之前先来看看另外一个定时任务Timer的使用
Timer类能够设置定时任务的相应方法不多,并且不够灵活,在高并发场景下效率不高。
这里以周期执行任务方法为例来看Timer内部是如何工作的
示例:
public class TimerDemo { public static void main(String[] args) { Timer timer = new Timer() ; timer.scheduleAtFixedRate(new TimerTask() { @Override public void run() { System.out.println(Thread.currentThread().getName()) ; } }, new Date(), 2000); timer.scheduleAtFixedRate(new TimerTask() { @Override public void run() { System.out.println(Thread.currentThread().getName() + ", task...") ; } }, new Date(), 2000); } }
这里很简单添加了2个周期任务都是每2秒输出当前线程的名称信息。
从控制台也能看出来,发现2个任务都是同一个线程来完成调度的。
在Timer类中有个成员变量:
这个类继承了Thread类。
new Timer时设置线程名称并启动线程:
启动线程后执行run方法:
mainLoop方法:
该方法死循环不停的从queue中获取任务执行。
当Timer执行时出现异常时会发生什么呢?
public class TimerDemo { static int a = 10 ; public static void main(String[] args) { Timer timer = new Timer() ; timer.scheduleAtFixedRate(new TimerTask() { @Override public void run() { if (a == 12) { throw new RuntimeException("发生错误") ; } a++ ; System.out.println(Thread.currentThread().getName()) ; } }, new Date(), 2000); timer.scheduleAtFixedRate(new TimerTask() { @Override public void run() { System.out.println(Thread.currentThread().getName() + ", task...") ; } }, new Date(), 2000); } }
执行结果:
1、当发生异常时整个Timer就停止了,这肯定不是我们想要的。
2、Timer对调度的支持是基于绝对时间的,而不是相对时间,所以它对系统时间的改变非常敏感。
知道了Timer的缺陷,接下来看ScheduledExecutorService
ScheduledExecutorService主要功能就是可以将定时任务与线程池功能结合使用。
ScheduledExecutorService是个接口它有一个实现类
ScheduledThreadPoolExecutor
而
ScheduledThreadPoolExecutor的父类是ThreadPoolExecutor。
ScheduledThreadPoolExecutor类方法:
有些方法是重写了父类的方法。如:submit,shutdown等方法。
通过Callable来执行延迟任务
示例:
public class ScheduledExecutorServiceDemo { public static void main(String[] args) throws Exception { ScheduledExecutorService sch = new ScheduledThreadPoolExecutor(5) ; ScheduledFuture<String> f1 = sch.schedule(() -> { System.out.println(Thread.currentThread().getName() + " 当前时间: "+ System.currentTimeMillis()) ; return "Task1" ; }, 5, TimeUnit.SECONDS) ; ScheduledFuture<String> f2 = sch.schedule(() -> { System.out.println(Thread.currentThread().getName() + " 当前时间: "+ System.currentTimeMillis()) ; return "Task2" ; }, 6, TimeUnit.SECONDS) ; System.out.println(f1.get()) ; System.out.println(f2.get()) ; } }
执行结果:
根据运行结果发现两个任务是同时执行的,第二个任务是又过了1秒就执行了。也就是多个任务同时执行时他们的起始时间都是一样的并不是一个执行完后另外一个要从0开始再计时。
通过Runnable来执行延迟任务
示例:
public class ScheduledExecutorServiceDemo2 { public static void main(String[] args) throws Exception { ScheduledExecutorService sch = new ScheduledThreadPoolExecutor(5) ; sch.schedule(() -> { System.out.println("A起始时间: " + Thread.currentThread().getName() + " 当前时间: "+ System.currentTimeMillis()) ; try { TimeUnit.SECONDS.sleep(3) ; } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("A结束时间: " + Thread.currentThread().getName() + " 当前时间: "+ System.currentTimeMillis()) ; }, 2, TimeUnit.SECONDS) ; sch.schedule(() -> { System.out.println("B起始时间: " + Thread.currentThread().getName() + " 当前时间: "+ System.currentTimeMillis()) ; try { TimeUnit.SECONDS.sleep(5) ; } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("B结束时间: " + Thread.currentThread().getName() + " 当前时间: "+ System.currentTimeMillis()) ; }, 2, TimeUnit.SECONDS) ; } }
执行结果:
执行周期性的任务scheduleAtFixedRate
示例(任务执行时间 > 周期时间):
public class ScheduledExecutorServiceDemo3 { public static void main(String[] args) throws Exception { ScheduledExecutorService sch = new ScheduledThreadPoolExecutor(5) ; sch.scheduleAtFixedRate(() -> { System.out.println("A起始时间: " + Thread.currentThread().getName() + " 当前时间: "+ System.currentTimeMillis()) ; try { TimeUnit.SECONDS.sleep(3) ; } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("A结束时间: " + Thread.currentThread().getName() + " 当前时间: "+ System.currentTimeMillis()) ; }, 1, 2, TimeUnit.SECONDS) ; } }
执行结果:
使用scheduleWithFixedDelay方法实现周期性任务执行
示例:
public class ScheduledExecutorServiceDemo4 { public static void main(String[] args) throws Exception { ScheduledExecutorService sch = new ScheduledThreadPoolExecutor(5) ; sch.scheduleWithFixedDelay(() -> { System.out.println("A起始时间: " + Thread.currentThread().getName() + " 当前时间: "+ System.currentTimeMillis()) ; try { TimeUnit.SECONDS.sleep(1) ; } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("A结束时间: " + Thread.currentThread().getName() + " 当前时间: "+ System.currentTimeMillis()) ; }, 1, 2, TimeUnit.SECONDS) ; } }
执行结果:
scheduleWithFixedDelay方法的作用是使得每次任务执行间隔为固定时间也就是scheduleWithFixedDelay方法的倒数第二个参数
公众号:Springboot实战案例锦集