Java多线程的ScheduledExecutorService使用
ScheduledExecutorService使用(一)定时任务的几种方案介绍(二)ScheduledExecutorService介绍(三)ScheduledExecutorService的使用3.1 schedule()使用(一)定时任务的几种方案介绍使用java做一个后台的定时任务,方案可以有如下几种:1、JDK自带的Timer2、JDK1.5+ 新增的ScheduledExecutorS
ScheduledExecutorService使用
(一)定时任务的几种方案介绍
使用java做一个后台的定时任务,方案可以有如下几种:
1、JDK自带的Timer
2、JDK1.5+ 新增的ScheduledExecutorService
3、Quartz :简单而强大的JAVA作业调度框架,可以支持动态的Cron语法
(二)ScheduledExecutorService介绍
ScheduledExecutorService出自java的并发包:java.util.concurrent,这个包下的很多需要探索。
今天我们就来使用一下ScheduledExecutorService实现定时任务:
ScheduledThreadPoolExecutor继承自ThreadPoolExecutor。它主要用来在给定的延迟之后运 行任务,或者定期执行任务。ScheduledThreadPoolExecutor的功能与Timer类似,但 ScheduledThreadPoolExecutor功能更强大、更灵活。Timer对应的是单个后台线程,而 ScheduledThreadPoolExecutor可以在构造函数中指定多个对应的后台线程数。
(三)ScheduledExecutorService的使用
ScheduledExecutorService包括三个方法:schedule()、scheduleAtFixedRate()、scheduleWithFixedDelay()。
3.1 schedule()使用
先上代码:
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的强大之处了。可以在构造函数中指定多个对应的后台线程数,并发的运行延迟任务。
3.2 scheduleFixedRate()使用
//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固定频率理解到)。
3.3scheduleWithFixedDelay()使用
//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表示任务执行周期等。
更多推荐
所有评论(0)