赞
踩
在上一章中,我们详细讲解线程池的作用,它可以在新的线程中执行任务,而且高效快捷,因为不用频繁地创建和销毁线程。
但是我们经常碰到这样的需求,任务不是立即执行,而是经过一段时间之后,才会执行。或者任务可以循环周期性地执行。那么怎么实现这样的需求呢?
在java中提供了ScheduledExecutorService接口,那么实现上面的需求。
一. ScheduledExecutorService接口
public interface ScheduledExecutorService extends ExecutorService {
// 给定的延迟时间delay之后,才会执行任务command
public ScheduledFuture> schedule(Runnable command,
long delay, TimeUnit unit);
// 给定的延迟时间delay之后,才会执行任务callable
public ScheduledFuture schedule(Callable callable,
long delay, TimeUnit unit);
/**
* 在给定的初始化延时initialDelay之后,固定频率地周期性执行任务command。
* 也就是说任务第一次运行时间是initialDelay,第二次运行时间是initialDelay+period,
* 第三次是initialDelay + period*2等等。 所以频率是相同地。
*
* 但是有一个问题,如果任务运行时间大于周期时间period该怎么办?
* 其实是这样的,在initialDelay之后开始运行任务,当任务完成之后,
* 将当前时间与initialDelay+period时间进行比较,如果小于initialDelay+period时间,那么等待,
* 如果大于initialDelay+period时间,那么就直接执行第二次任务
*
*/
public ScheduledFuture> scheduleAtFixedRate(Runnable command,
long initialDelay,
long period,
TimeUnit unit);
/**
* 在给定的初始化延时initialDelay之后,开始执行任务,任务执行完成之后,
* 等待delay时间,再一次执行任务。
* 因为它是等待任务完成之后,再进行延迟,就不会受任务完成时间长短地影响。
*/
public ScheduledFuture> scheduleWithFixedDelay(Runnable command,
long initialDelay,
long delay,
TimeUnit unit);
}
ScheduledExecutorService接口定义了四个方法:
schedule的两个方法,延时delay时间后执行任务。区别Callable参数可以获取任务完成的结果值,Runnable参数的不会得到结果值。
scheduleAtFixedRate方法:在延时initialDelay时间之后,开始第一次执行任务,然后每隔周期时间period,再次执行任务。注意如果任务消耗时间大于周期时间period,会等待任务完成之后,才再次执行任务。
scheduleWithFixedDelay方法:在延时initialDelay时间之后,开始第一次执行任务,任务执行完成之后,再延时delay时间,然后再次执行任务。
下面我们结合例子来说明。
二. 延迟执行任务
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
class MyRun implements Runnable {
private long start;
public MyRun() {
this.start = System.currentTimeMillis();
}
@Override
public void run() {
long time = System.currentTimeMillis() - start;
System.out.println("--"+Thread.currentThread().getName()+"开始运行 time=="+time);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
System.out.println(Thread.currentThread().getName()+" 发生中断异常 exception=="+e.getMessage());
}
time = System.currentTimeMillis() - start;
System.out.println("======="+Thread.currentThread().getName()+"结束 time=="+time);
}
}
class MThreadFactory implements ThreadFactory {
private int sequenceNumber = 0;
@Override
public Thread newThread(Runnable r) {
return new Thread(r, "线程"+(++sequenceNumber));
}
}
public class ScheduledExecutorServiceTest {
public static void main(String[] args) {
ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor(new MThreadFactory());
MyRun run = new MyRun();
service.schedule(run, 1000, TimeUnit.MILLISECONDS);
}
}
运行结果:
--线程1开始运行 time==1004
=======线程1结束 time==2006
可以看出任务run的确延时了1秒之后才执行的。
三. 周期性执行任务
3.1 scheduleAtFixedRate方法
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
class MyRun implements Runnable {
private long start;
public MyRun() {
this.start = System.currentTimeMillis();
}
@Override
public void run() {
long time = System.currentTimeMillis() - start;
System.out.println("--"+Thread.currentThread().getName()+"开始运行 time=="+time);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
System.out.println(Thread.currentThread().getName()+" 发生中断异常 exception=="+e.getMessage());
}
time = System.currentTimeMillis() - start;
System.out.println("======="+Thread.currentThread().getName()+"结束 time=="+time);
}
}
class MThreadFactory implements ThreadFactory {
private int sequenceNumber = 0;
@Override
public Thread newThread(Runnable r) {
return new Thread(r, "线程"+(++sequenceNumber));
}
}
public class ScheduledExecutorServiceTest {
public static void main(String[] args) {
ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor(new MThreadFactory());
MyRun run = new MyRun();
service.scheduleAtFixedRate(run, 0, 2000, TimeUnit.MILLISECONDS);
}
}
运行结果:
--线程1开始运行 time==1
=======线程1结束 time==1005
--线程1开始运行 time==2005
=======线程1结束 time==3009
--线程1开始运行 time==4003
=======线程1结束 time==5007
--线程1开始运行 time==6002
=======线程1结束 time==7007
--线程1开始运行 time==8004
=======线程1结束 time==9005
--线程1开始运行 time==10004
=======线程1结束 time==11008
调用了scheduleAtFixedRate方法,设置周期时间是2000毫秒,发现任务run的确是每隔2000毫秒执行一次。那是因为我们任务消耗时间是1000毫秒,小于周期时间。如果我们将周期时间改为500毫秒会出现什么情况?
运行结果:
--线程1开始运行 time==1
=======线程1结束 time==1005
--线程1开始运行 time==1006
=======线程1结束 time==2011
--线程1开始运行 time==2011
=======线程1结束 time==3015
--线程1开始运行 time==3015
=======线程1结束 time==4019
--线程1开始运行 time==4019
=======线程1结束 time==5023
--线程1开始运行 time==5024
=======线程1结束 time==6028
--线程1开始运行 time==6028
=======线程1结束 time==7032
我们发现任务run并不是每隔周期时间500毫秒执行一次,而是每隔任务完成时间1000毫秒执行一次.
所以对于scheduleAtFixedRate方法来说:
如果执行完任务后,发现时间没有到定时的周期时间,那么就会等待,直到时间到了再执行任务。
如果执行完任务后,发现时间超过定时的周期时间,那么就直接再次执行任务。
3.2 scheduleWithFixedDelay方法
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
class MyRun implements Runnable {
private long start;
public MyRun() {
this.start = System.currentTimeMillis();
}
@Override
public void run() {
long time = System.currentTimeMillis() - start;
System.out.println("--"+Thread.currentThread().getName()+"开始运行 time=="+time);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
System.out.println(Thread.currentThread().getName()+" 发生中断异常 exception=="+e.getMessage());
}
time = System.currentTimeMillis() - start;
System.out.println("======="+Thread.currentThread().getName()+"结束 time=="+time);
}
}
class MThreadFactory implements ThreadFactory {
private int sequenceNumber = 0;
@Override
public Thread newThread(Runnable r) {
return new Thread(r, "线程"+(++sequenceNumber));
}
}
public class ScheduledExecutorServiceTest {
public static void main(String[] args) {
ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor(new MThreadFactory());
MyRun run = new MyRun();
service.scheduleWithFixedDelay(run, 0, 500, TimeUnit.MILLISECONDS);
}
}
运行结果:
--线程1开始运行 time==1
=======线程1结束 time==1004
--线程1开始运行 time==1509
=======线程1结束 time==2513
--线程1开始运行 time==3013
=======线程1结束 time==4016
--线程1开始运行 time==4519
=======线程1结束 time==5524
--线程1开始运行 time==6028
=======线程1结束 time==7029
--线程1开始运行 time==7531
=======线程1结束 time==8535
--线程1开始运行 time==9040
=======线程1结束 time==10044
scheduleWithFixedDelay方法的意义就是当任务完成之后,延迟delay时间,再一次执行任务,一直循环下去。
总结
ScheduledExecutorService接口中的方法已经详细举例分析了,如果你只是想使用定时线程池的话,那么你已经知道该如何使用了。但是如果你想知道定时线程池是怎么实现的话,请看我的下一篇文章。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。