java ScheduledExecutorService实现定时任务

使用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方法源码

扫描二维码关注公众号,回复: 9401018 查看本文章
/**
 * 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()方法。
发布了287 篇原创文章 · 获赞 44 · 访问量 15万+

猜你喜欢

转载自blog.csdn.net/mqdxiaoxiao/article/details/103715672