使用scheduleAtFixedRate方法
private ScheduledExecutorService pool = Executors.newScheduledThreadPool(5);
private ScheduledFuture future;
// 开启定时器
private void startTask() {
stopTask();
future = pool.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Log.d("TimerTask", "do something...");
}
}, 2, 2, TimeUnit.SECONDS);
}
// 停止定时器
private void stopTask() {
if (future != null && !future.isCancelled()) {
//true:执行中的任务也会中断,false:执行中的任务不中断
future.cancel(true);
}
}
使用scheduleWithFixedDelay方法
private ScheduledExecutorService pool = Executors.newScheduledThreadPool(5);
private ScheduledFuture future;
// 开启定时器
private void startTask() {
stopTask();
future = pool.scheduleWithFixedDelay(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Log.d("TimerTask", "do something...");
}
}, 2, 2, TimeUnit.SECONDS);
}
// 停止定时器
private void stopTask() {
if (future != null && !future.isCancelled()) {
//true:执行中的任务也会中断,false:执行中的任务不中断
future.cancel(true);
}
}
scheduleAtFixedRate和scheduleWithFixedDelay的区别
既然scheduleAtFixedRate和scheduleWithFixedDelay方法都可以创建定时任务,那么这两者有何区别呢?
我们先看下以上两个示例代码打印的日志
scheduleAtFixedRate定时任务的日志
2019-12-26 15:05:04.527 23921-23977/com.him.hisapp D/TimerTask: do something...
2019-12-26 15:05:06.527 23921-23977/com.him.hisapp D/TimerTask: do something...
2019-12-26 15:05:08.527 23921-23977/com.him.hisapp D/TimerTask: do something...
2019-12-26 15:05:10.527 23921-23977/com.him.hisapp D/TimerTask: do something...
2019-12-26 15:05:12.527 23921-23977/com.him.hisapp D/TimerTask: do something...
2019-12-26 15:05:14.528 23921-23977/com.him.hisapp D/TimerTask: do something...
2019-12-26 15:05:16.527 23921-23977/com.him.hisapp D/TimerTask: do something...
2019-12-26 15:05:18.527 23921-23977/com.him.hisapp D/TimerTask: do something...
2019-12-26 15:05:20.527 23921-23977/com.him.hisapp D/TimerTask: do something...
2019-12-26 15:05:22.526 23921-23977/com.him.hisapp D/TimerTask: do something...
scheduleWithFixedDelay定时任务的日志
2019-12-26 15:09:48.579 24451-24516/com.him.hisapp D/TimerTask: do something...
2019-12-26 15:09:51.580 24451-24516/com.him.hisapp D/TimerTask: do something...
2019-12-26 15:09:54.580 24451-24517/com.him.hisapp D/TimerTask: do something...
2019-12-26 15:09:57.582 24451-24517/com.him.hisapp D/TimerTask: do something...
2019-12-26 15:10:00.584 24451-24517/com.him.hisapp D/TimerTask: do something...
2019-12-26 15:10:03.584 24451-24517/com.him.hisapp D/TimerTask: do something...
2019-12-26 15:10:06.585 24451-24517/com.him.hisapp D/TimerTask: do something...
2019-12-26 15:10:09.588 24451-24517/com.him.hisapp D/TimerTask: do something...
2019-12-26 15:10:12.589 24451-24517/com.him.hisapp D/TimerTask: do something...
2019-12-26 15:10:15.590 24451-24517/com.him.hisapp D/TimerTask: do something...
在以上两个示例代码中定时任务的间隔都是2秒,任务执行时间都是1秒,但是注意看下log,scheduleAtFixedRate创建的定时任务打印的log的时间间隔都是2秒,但是scheduleWithFixedDelay创建的定时任务的log时间间隔却是3秒。
这是因为scheduleAtFixedRate创建的定时任务每隔2000就会开始新的任务
而scheduleWithFixedDelay创建的定时任务是会等前一个任务执行完(1秒)然后2秒后再执行新的任务,所以两个任务间的间隔变成3秒
但是对于scheduleAtFixedRate创建的任务,如果说任务执行时间大于定时间隔,那么两个任务间的实际间隔就会大于定时器间隔,也就是会等于任务执行时间。这样就会保证同一时间同一个定时器内只有一个任务运行,而不能并发运行,我们可以修改下以上示例一的代码,把任务执行时间改成4秒,然后在看下打印的日志时间间隔是否为4秒
private ScheduledExecutorService pool = Executors.newScheduledThreadPool(5);
private ScheduledFuture future;
// 开启定时器
private void startTask() {
stopTask();
future = pool.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
try {
Thread.sleep(4000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Log.d("TimerTask", "do something...");
}
}, 2, 2, TimeUnit.SECONDS);
}
// 停止定时器
private void stopTask() {
if (future != null && !future.isCancelled()) {
//true:执行中的任务也会中断,false:执行中的任务不中断
future.cancel(true);
}
}
2019-12-26 15:32:30.827 26967-27023/com.him.hisapp D/TimerTask: do something...
2019-12-26 15:32:34.829 26967-27023/com.him.hisapp D/TimerTask: do something...
2019-12-26 15:32:38.830 26967-27023/com.him.hisapp D/TimerTask: do something...
2019-12-26 15:32:42.832 26967-27023/com.him.hisapp D/TimerTask: do something...
2019-12-26 15:32:46.833 26967-27023/com.him.hisapp D/TimerTask: do something...
2019-12-26 15:32:50.834 26967-27023/com.him.hisapp D/TimerTask: do something...
2019-12-26 15:32:54.835 26967-27023/com.him.hisapp D/TimerTask: do something...
2019-12-26 15:32:58.836 26967-27023/com.him.hisapp D/TimerTask: do something...
2019-12-26 15:33:02.836 26967-27023/com.him.hisapp D/TimerTask: do something...
2019-12-26 15:33:06.836 26967-27023/com.him.hisapp D/TimerTask: do something...
bingo,日志的时间间隔确实是等于任务执行时间4秒
源码
我们以上通过日志验证的scheduleAtFixedRate和scheduleWithFixedDelay的区别在源码里都有说明
scheduleAtFixedRate方法源码
/**
* Creates and executes a periodic action that becomes enabled first
* after the given initial delay, and subsequently with the given
* period; that is, executions will commence after
* {@code initialDelay}, then {@code initialDelay + period}, then
* {@code initialDelay + 2 * period}, and so on.
*
* <p>The sequence of task executions continues indefinitely until
* one of the following exceptional completions occur:
* <ul>
* <li>The task is {@linkplain Future#cancel explicitly cancelled}
* via the returned future.
* <li>The executor terminates, also resulting in task cancellation.
* <li>An execution of the task throws an exception. In this case
* calling {@link Future#get() get} on the returned future will
* throw {@link ExecutionException}.
* </ul>
* Subsequent executions are suppressed. Subsequent calls to
* {@link Future#isDone isDone()} on the returned future will
* return {@code true}.
*
* <p>If any execution of this task takes longer than its period, then
* subsequent executions may start late, but will not concurrently
* execute.
*
* @param command the task to execute
* @param initialDelay the time to delay first execution
* @param period the period between successive executions
* @param unit the time unit of the initialDelay and period parameters
* @return a ScheduledFuture representing pending completion of
* the series of repeated tasks. The future's {@link
* Future#get() get()} method will never return normally,
* and will throw an exception upon task cancellation or
* abnormal termination of a task execution.
* @throws RejectedExecutionException if the task cannot be
* scheduled for execution
* @throws NullPointerException if command is null
* @throws IllegalArgumentException if period less than or equal to zero
*/
public ScheduledFuture<?> scheduleAtFixedRate(Runnable command,
long initialDelay,
long period,
TimeUnit unit);
scheduleWithFixedDelay方法源码
/**
* Creates and executes a periodic action that becomes enabled first
* after the given initial delay, and subsequently with the
* given delay between the termination of one execution and the
* commencement of the next.
*
* <p>The sequence of task executions continues indefinitely until
* one of the following exceptional completions occur:
* <ul>
* <li>The task is {@linkplain Future#cancel explicitly cancelled}
* via the returned future.
* <li>The executor terminates, also resulting in task cancellation.
* <li>An execution of the task throws an exception. In this case
* calling {@link Future#get() get} on the returned future will
* throw {@link ExecutionException}.
* </ul>
* Subsequent executions are suppressed. Subsequent calls to
* {@link Future#isDone isDone()} on the returned future will
* return {@code true}.
*
* @param command the task to execute
* @param initialDelay the time to delay first execution
* @param delay the delay between the termination of one
* execution and the commencement of the next
* @param unit the time unit of the initialDelay and delay parameters
* @return a ScheduledFuture representing pending completion of
* the series of repeated tasks. The future's {@link
* Future#get() get()} method will never return normally,
* and will throw an exception upon task cancellation or
* abnormal termination of a task execution.
* @throws RejectedExecutionException if the task cannot be
* scheduled for execution
* @throws NullPointerException if command is null
* @throws IllegalArgumentException if delay less than or equal to zero
*/
public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command,
long initialDelay,
long delay,
TimeUnit unit);
总结
- scheduleAtFixedRate定时任务的实际时间间隔为定时器的时间间隔,除非任务的执行时间超过定时器时间间隔,那么实际的时间间隔为任务的执行时间。
- scheduleWithFixedDelay定时任务的实际时间间隔为定时器时间间隔+任务执行时间,也就是会等上一任务执行完才会定时开始下一个任务。
- ScheduledExecutorService是由Executors.newScheduledThreadPool创建的线程池,所以可以支持创建多个定时器并发执行。
- 若要停止定时任务,可以通过调用scheduleAtFixedRate或scheduleWithFixedDelay方法返回的ScheduledFuture对象的cancel()方法。