赞
踩
使用java做一个后台的定时任务,方案可以有如下几种:
1、JDK自带的Timer
2、JDK1.5+ 新增的ScheduledExecutorService
3、Quartz :简单而强大的JAVA作业调度框架,可以支持动态的Cron语法
ScheduledExecutorService出自java的并发包:java.util.concurrent,这个包下的很多需要探索。
今天我们就来使用一下ScheduledExecutorService实现定时任务:
ScheduledThreadPoolExecutor继承自ThreadPoolExecutor。它主要用来在给定的延迟之后运 行任务,或者定期执行任务。ScheduledThreadPoolExecutor的功能与Timer类似,但 ScheduledThreadPoolExecutor功能更强大、更灵活。Timer对应的是单个后台线程,而 ScheduledThreadPoolExecutor可以在构造函数中指定多个对应的后台线程数。
ScheduledExecutorService包括三个方法:schedule()、scheduleAtFixedRate()、scheduleWithFixedDelay()。
先上代码:
public static void main(String[] args) { scheduleTest(); //scheduleFixedRate(); //scheduleWithFixedDelay(); } //schedule()的用法,可以对任务进行延迟处理 static void scheduleTest(){ ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(1); //获取当前时间 long cur = System.currentTimeMillis(); scheduledExecutorService.schedule(new Runnable() { @Override public void run() { //当前任务执行时候,对应的时间 System.out.println("延迟了"+(System.currentTimeMillis() - cur) + "ms"); } },3000, TimeUnit.MILLISECONDS); scheduledExecutorService.shutdown(); }
可以看到schedule()方法下需要三个参数,分别是:一个runnable线程,延迟时间,时间单位。
"C:\Program Files\Java\
延迟了3013ms
Process finished with exit code 0
实际情况下,run方法体中代码执行时间延迟了3s执行,多出来的是建立线程花费的时间。
此时再加入这样的条件,如果线程中的任务需要一定的执行时间,如果再有一个延迟任务执行呢?代码如下
public static void main(String[] args) { scheduleTest(); //scheduleFixedRate(); //scheduleWithFixedDelay(); } //schedule()的用法,可以对任务进行延迟处理 static void scheduleTest(){ ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(1); //获取当前时间 long cur = System.currentTimeMillis(); scheduledExecutorService.schedule(new Runnable() { @Override public void run() { //当前任务执行时候,对应的时间 System.out.println("第一次延迟了"+(System.currentTimeMillis() - cur) + "ms"); //任务执行需要时间 try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } } },3000, TimeUnit.MILLISECONDS); scheduledExecutorService.schedule(new Runnable() { @Override public void run() { //当前任务执行时候,对应的时间 System.out.println("第二次延迟了"+(System.currentTimeMillis() - cur) + "ms"); //任务执行需要时间 try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } } },3000, TimeUnit.MILLISECONDS); scheduledExecutorService.shutdown(); }
线程池中线程数量指定为1,运行结果如下:
第一次延迟了3017ms
第二次延迟了6022ms
Process finished with exit code 0
可以看到第二个任务需要等到第一个任务执行完成以后才进行执行。等待时间为延迟时间+任务时间。这时,如果将线程数目改为2,再次执行:
第一次延迟了3007ms
第二次延迟了3007ms
Process finished with exit code 0
可以看到ScheduledExecutorService的强大之处了。可以在构造函数中指定多个对应的后台线程数,并发的运行延迟任务。
//scheduleAtFixedRate()的用法 //在schedule下,加了周期运行的条件。 static void scheduleFixedRate(){ ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(1); //获取当前时间 long cur = System.currentTimeMillis(); scheduledExecutorService.scheduleAtFixedRate(new Runnable() { @Override public void run() { //当前任务执行时候,对应的时间 System.out.println("延迟了"+(System.currentTimeMillis() - cur) + "ms"); try { Thread.sleep(3000); } catch (InterruptedException e) { e.printStackTrace(); } } },3000,2000,TimeUnit.MILLISECONDS); }
相比于schedule()方法,多了一个参数period,就是可以指定周期执行。如上代码,周期为2s。但其中的任务运行时间是3s。结果是:
"C:\Program Files\Java\jdk1.8.0_101\bin
延迟了3016ms
延迟了6020ms
延迟了9036ms
延迟了12040ms
延迟了15043ms
延迟了18045ms
Process finished with exit code -1
首先第一次延时3016ms是因为指定的initdelay为3s。但后面的任务运行并不是按照period的周期执行,而是任务的运行时间执行。也就是说设定的周期时间不足以完成线程任务,但scheduleFixedRate达到设定的延迟时间了就要执行下一次。(可以从字面意思FixedRate固定频率理解到)。
//scheduleWithFixedDelay()用法 //也是加了周期运行的条件,但是必须是等到上一个任务结束后,进行周期循环。周期时间就是任务运行时间+delay static void scheduleWithFixedDelay(){ ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(1); //获取当前时间 long cur = System.currentTimeMillis(); scheduledExecutorService.scheduleWithFixedDelay(new Runnable() { @Override public void run() { //当前任务执行时候,对应的时间 System.out.println("延迟了"+(System.currentTimeMillis() - cur) + "ms"); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } } },3000,2000,TimeUnit.MILLISECONDS); }
相比于scheduleFixedRate(),scheduleWithFixedDelay()是每次都要把任务执行完成后再延迟固定时间后再执行下一次。结果如下:周期为任务运行时间+delay(指定周期时间)
C:\Program Files\Java\
延迟了3015ms
延迟了7038ms
延迟了11060ms
延迟了15078ms
延迟了19101ms
Process finished with exit code -1
ScheduledThreadPoolExecutor类继承自ThreadPoolExecutor,除了拥有普通线程池的功能之外,因为实现了ScheduledExecutorService接口,因而同时拥有定时器的功能。
首先构造方法全部是调用了父类ThreadPoolExecutor的。
实例化后执行的schedule()方法调用了定时器,将传入的Runnable对象封装成ScheduledFutureTask对象,ScheduledFutureTask类实现了RunnableScheduledFuture接口。ScheduledFutureTask类就包含了time表示任务执行时间,period表示任务执行周期等。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。