ScheduledExecutorService定时周期执行指定的任务 ,关于scheduleAtFixedRate 和 scheduleWithFixedDelay使用区别

来源:互联网 发布:个人域名申请 编辑:程序博客网 时间:2024/05/19 02:40

在项目中使用到了多线程定时执行指定任务中发现以下一些问题:

/**     * 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.     * If any execution of the task     * encounters an exception, subsequent executions are suppressed.     * Otherwise, the task will only terminate via cancellation or     * termination of the executor.  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 task, and whose {@code get()} method will throw an     *         exception upon cancellation     * @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);command:执行线程initialDelay:初始化延时period:两次开始执行最小间隔时间unit:计时单位对于scheduleAtFixedRate方法,当我们要执行的任务大于我们指定的执行间隔时会怎么样呢?对于中文API中的注释,我们可能会被忽悠,认为无论怎么样,它都会按照我们指定的间隔进行执行,其实当执行任务的时间大于我们指定的间隔时间时,它并不会在指定间隔时开辟一个新的线程并发执行这个任务。而是等待该线程执行完毕。    /**     * 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.  If any execution of the task     * 之间。     * encounters an exception, subsequent executions are suppressed.     * Otherwise, the task will only terminate via cancellation or     * termination of the executor.     *如果任务的任何执行遇到异常,则会抑制随后的执行。否则,任务将仅通过执行程序的取消或终止而终止。     * @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 task, and whose {@code get()} method will throw an     *         exception upon cancellation     * @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);command:执行线程initialDelay:初始化延时period:前一次执行结束到下一次执行开始的间隔时间(间隔执行延迟时间)unit:计时单位这个是以delay为固定延迟时间,按照一定的等待时间来执行任务,initialDelay意义与上面的相同。如果执行初始化延时为0秒,间隔2秒,如果执行任务用了10秒,那下个任务开始就是第12秒后开始执行。这个是优先保证任务执行的间隔。

以上是源码介绍,翻译不好,希望大家指出。

这里用三个定时任务说明下问题,到时根据自己需求制定初时时间、间隔时间、以及线程任务数。

package com;import java.util.concurrent.Executors;import java.util.concurrent.ScheduledExecutorService;import java.util.concurrent.TimeUnit;/** *  * @author ZL *  2017年8月29日 */public class Schedule {    private static ScheduledExecutorService excutor = Executors.newSingleThreadScheduledExecutor();    /**     * scheduleAtFixedRate     * 按指定频率周期执行某个任务 <br>     * 初始化延迟0ms开始执行,每隔2ms重新执行一次任务。     */    public void one() {        excutor.scheduleAtFixedRate(new EchoServerone(), // 执行线程                0, // 初始化延迟                2000, // 两次开始的执行的最小时间间隔                TimeUnit.MILLISECONDS // 计时单位        );    }    /**     * scheduleAtFixedRate     * 按指定频率周期执行某个任务 <br>     * 初始化延迟0ms开始执行,每隔2ms重新执行一次任务。     */    public void two() {        excutor.scheduleAtFixedRate(new EchoServertwo(), // 执行线程                0, // 初始化延迟                2000, // 两次开始的执行的最小时间间隔                TimeUnit.MILLISECONDS // 计时单位        );    }    /**     * scheduleWithFixedDelay     * 按指定频率周期执行某个任务 <br>     * 初始化延迟0ms开始执行,每隔2ms重新执行一次任务。     */    public void three() {        excutor.scheduleWithFixedDelay(new EchoServerthree(), // 执行线程                0, // 初始化延迟                2000, // 前一次执行结束到下一次执行开始的间隔时间                TimeUnit.MILLISECONDS);    }    public static void main(String[] args) {        Schedule schedule = new Schedule();        schedule.one();         schedule.two();         schedule.three();    }}
package com;/** * 线程任务一 * @author ZL *  2017年8月29日 */public class EchoServerone implements Runnable {    @Override    public void run() {        System.out.println("线程任务一开始执行"+DateUtils.getnewTime());        try {            Thread.sleep(10000);        } catch (InterruptedException e) {            // TODO Auto-generated catch block            e.printStackTrace();        }        System.out.println("线程任务一执行结束"+DateUtils.getnewTime());    }}
package com;/** * 线程任务二 * @author ZL *  2017年8月29日 */public class EchoServertwo implements Runnable {    @Override    public void run() {        System.out.println("线程任务二开始执行"+DateUtils.getnewTime());        try {            Thread.sleep(10000);        } catch (InterruptedException e) {            // TODO Auto-generated catch block            e.printStackTrace();        }        System.out.println("线程任务二 执行结束"+DateUtils.getnewTime());    }}
package com;/** * 线程任务三 * @author ZL *  2017年8月29日 */public class EchoServerthree implements Runnable {    @Override    public void run() {        System.out.println("线程任务三开始执行"+DateUtils.getnewTime());        try {            Thread.sleep(10000);        } catch (InterruptedException e) {            // TODO Auto-generated catch block            e.printStackTrace();        }        System.out.println("线程任务三执行结束"+DateUtils.getnewTime());    }}

运行结果:

线程任务一开始执行2017-08-29 17:07:25线程任务一执行结束2017-08-29 17:07:35线程任务二开始执行2017-08-29 17:07:35线程任务二 执行结束2017-08-29 17:07:45线程任务三开始执行2017-08-29 17:07:45线程任务三执行结束2017-08-29 17:07:55线程任务一开始执行2017-08-29 17:07:55线程任务一执行结束2017-08-29 17:08:05线程任务二开始执行2017-08-29 17:08:05线程任务二 执行结束2017-08-29 17:08:15线程任务一开始执行2017-08-29 17:08:15线程任务一执行结束2017-08-29 17:08:25线程任务二开始执行2017-08-29 17:08:25线程任务二 执行结束2017-08-29 17:08:35线程任务一开始执行2017-08-29 17:08:35线程任务一执行结束2017-08-29 17:08:45线程任务二开始执行2017-08-29 17:08:45线程任务二 执行结束2017-08-29 17:08:55线程任务一开始执行2017-08-29 17:08:55

看到运行结果肯定会发现,定时任务三只在初次运行时执行后由于每个线程执行中都会有10秒的休眠,,然后定时任务三就不运行了,三个定时任务的间隔时间都为两秒。

解决办法是:

修改的代码:

/***   把scheduleWithFixedDelay换成scheduleAtFixedRate     * 按指定频率周期执行某个任务 <br>     * 初始化延迟0ms开始执行,每隔2ms重新执行一次任务。     */    public void three() {        excutor.scheduleAtFixedRate(new EchoServerthree(), // 执行线程                0, // 初始化延迟                2000, // 前一次执行结束到下一次执行开始的间隔时间                TimeUnit.MILLISECONDS);    }

运行结果:

线程任务一开始执行2017-08-29 17:29:01线程任务一执行结束2017-08-29 17:29:11线程任务二开始执行2017-08-29 17:29:11线程任务二 执行结束2017-08-29 17:29:21线程任务三开始执行2017-08-29 17:29:21线程任务三执行结束2017-08-29 17:29:31线程任务一开始执行2017-08-29 17:29:31线程任务一执行结束2017-08-29 17:29:41线程任务二开始执行2017-08-29 17:29:41线程任务二 执行结束2017-08-29 17:29:51线程任务三开始执行2017-08-29 17:29:51线程任务三执行结束2017-08-29 17:30:01线程任务一开始执行2017-08-29 17:30:01线程任务一执行结束2017-08-29 17:30:11线程任务二开始执行2017-08-29 17:30:11线程任务二 执行结束2017-08-29 17:30:21线程任务三开始执行2017-08-29 17:30:21线程任务三执行结束2017-08-29 17:30:31线程任务一开始执行2017-08-29 17:30:31线程任务一执行结束2017-08-29 17:30:41线程任务二开始执行2017-08-29 17:30:41线程任务二 执行结束2017-08-29 17:30:51

这样运行后的结果就不会出现有线程任务不执行的后果了。需要那种根据自己需求吧。

阅读全文
0 0
原创粉丝点击