Java 定时线程池各个方法的区别 Java周期执行线程池各个方法的区别 ScheduledExecutorService schedulerService

时间:2023-04-02 14:02:06

Java 定时线程池各个方法的区别 Java周期执行线程池各个方法的区别 ScheduledExecutorService schedulerService

一、概述

        Java JDK提供的java.util.concurrent.Executors 线程池工具类中,有四个线程池创建的方法,分别是:

  • newFixedThreadPool  (固定数目线程的线程池)
  • newCachedThreadPool (可缓存线程的线程池)
  • newSingleThreadExecutor (单线程的线程池)
  • newScheduledThreadPool (定时及周期执行的线程池)

        本文将整理 newScheduledThreadPool 定时线程池中各个方法的区别。

二、方法区别

        1、scheduler , 无返回值

/**
 * Description: schedule 方法,只执行一次 , 没有返回值
 * @param executor
 * @return  void
 * @version v1.0
 * @author wu
 * @date 2023/2/27 22:27
 */
public static void schedulerNoReturn(ScheduledExecutorService executor){
    // 1、schedule 方法,只执行一次 , 没有返回值
    executor.schedule(()->{
        System.out.println("schedulerNoReturn ==");
    },1, TimeUnit.SECONDS);
}

        2、scheduler , 有返回值

/**
 * Description: schedule 方法,只执行一次 , 没有返回值
 * @param executor
 * @return  void
 * @version v1.0
 * @author wu
 * @date 2023/2/27 22:27
 */
public static String schedulerYesReturn(ScheduledExecutorService executor) throws ExecutionException, InterruptedException {
    // 1、schedule 方法,只执行一次 , 没有返回值
    final ScheduledFuture<String> future = executor.schedule(() -> {
        System.out.println("schedulerYesReturn ==");
        return DateUtils.getDateTime();
    }, 1, TimeUnit.SECONDS);
    return future.get();
}

        3、固定时间执行: scheduleAtFixedRate --- 延迟5秒测试

/**
 * Description: 固定时间执行 , 和当前任务是否执行完毕 无关
 * @param executor
 * @param expireTime --- 过期时间,单位:秒
 * @return  void
 * @version v1.0
 * @author wu
 * @date 2023/2/27 22:39
 */
public static void scheduleAtFixedRateTest(ScheduledExecutorService executor , long expireTime){
    // 2、固定时间执行 , 每隔5s 执行一次 。 sleep > delay 时,以 sleep 为准
    // sleep < delay , 以 delay  为准
    executor.scheduleAtFixedRate(()->{
        try {
            TimeUnit.SECONDS.sleep(expireTime);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("scheduleAtFixedRate ===·"+ DateUtils.getDateTime());
    },1,5,TimeUnit.SECONDS);
}

        3.1、测试 - 固定执行时间5s :


        scheduleAtFixedRateTest(executor,4L); // 小于
        scheduleAtFixedRateTest(executor,5L); // 等于
        scheduleAtFixedRateTest(executor,6L); // 大于
        

        3.2、测试结果分别如下:

--- 方法执行时间为: 4s 
scheduleAtFixedRate ===·2023-03-26 19:34:19
scheduleAtFixedRate ===·2023-03-26 19:34:24
scheduleAtFixedRate ===·2023-03-26 19:34:29
scheduleAtFixedRate ===·2023-03-26 19:34:34

--- 方法执行时间为: 5s 
scheduleAtFixedRate ===·2023-03-26 19:36:02
scheduleAtFixedRate ===·2023-03-26 19:36:07
scheduleAtFixedRate ===·2023-03-26 19:36:12
scheduleAtFixedRate ===·2023-03-26 19:36:17

--- 方法执行时间为: 6s 
scheduleAtFixedRate ===·2023-03-26 19:39:04
scheduleAtFixedRate ===·2023-03-26 19:39:10
scheduleAtFixedRate ===·2023-03-26 19:39:16
scheduleAtFixedRate ===·2023-03-26 19:39:22

        4、固定时间执行+延迟时间后,再执行 : scheduleWithFixedDelay

/**
 * Description: 固定时间执行,当前任务执行完毕后,再间隔 delay 秒后执行
 * @param executor
 * @param expireTime --- 过期时间,单位:秒
 * @return  void
 * @version v1.0
 * @author wu
 * @date 2023/2/27 22:41
 */
public static void scheduleWithFixedDelayTest(ScheduledExecutorService executor , long expireTime){
    // 3、固定时间执行,当前任务执行完毕后,再间隔 delay 秒后执行
    //  下次执行时间为: sleep + delay
    executor.scheduleWithFixedDelay(()->{
        try {
            TimeUnit.SECONDS.sleep(expireTime);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("scheduleWithFixedDelay ===·"+ DateUtils.getDateTime());
    },1,5,TimeUnit.SECONDS);
}

        4.1、测试 - 固定执行时间5s :


        scheduleWithFixedDelayTest(executor,4L); // 小于
        scheduleWithFixedDelayTest(executor,5L); // 等于
        scheduleWithFixedDelayTest(executor,6L); // 大于
        

        4.2、测试结果分别如下:

--- 方法执行时间为: 4s 
scheduleWithFixedDelay ===·2023-03-26 19:44:11
scheduleWithFixedDelay ===·2023-03-26 19:44:20
scheduleWithFixedDelay ===·2023-03-26 19:44:29
scheduleWithFixedDelay ===·2023-03-26 19:44:38


--- 方法执行时间为: 5s 
scheduleWithFixedDelay ===·2023-03-26 19:46:00
scheduleWithFixedDelay ===·2023-03-26 19:46:10
scheduleWithFixedDelay ===·2023-03-26 19:46:20
scheduleWithFixedDelay ===·2023-03-26 19:46:30

--- 方法执行时间为: 6s
scheduleWithFixedDelay ===·2023-03-26 19:47:33
scheduleWithFixedDelay ===·2023-03-26 19:47:44
scheduleWithFixedDelay ===·2023-03-26 19:47:55
scheduleWithFixedDelay ===·2023-03-26 19:48:06
 

三、总结

        1、定时线程池中,四个方法位于 ScheduledExecutorService 类中

public ScheduledFuture<?> schedule(Runnable command,
                                   long delay, TimeUnit unit);

public <V> ScheduledFuture<V> schedule(Callable<V> callable,
                                       long delay, TimeUnit unit);
                                       
public ScheduledFuture<?> scheduleAtFixedRate(Runnable command,
                                              long initialDelay,
                                              long period,
                                              TimeUnit unit);
                                              
public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command,
                                                 long initialDelay,
                                                 long delay,
                                                 TimeUnit unit);
                                                 
                                       

 

Java 定时线程池各个方法的区别 Java周期执行线程池各个方法的区别 ScheduledExecutorService schedulerService

 

        2、schedule 的两个方法特点是:

                只执行一次,可以根据实际需要,有返回值和无返回值。

        3、scheduleAtFixedRate :

                固定速率执行, 当方法执行时间 > period 时,则会按照 方法执行时间 周期的速率进行执行 ; 当方法执行时间 <= period 时,则按照 period 周期速率执行。 【二 - 3.2、测试结果分别如下】

        4、scheduleWithFixedDelay :

                固定速率执行,执行的周期速率为:方法执行时间 + period 。 【二 - 4.2、测试结果分别如下】

        5、scheduleAtFixedRate 和 scheduleWithFixedDelay 区别:

  • scheduleAtFixedRate : 方法执行时间 > period ,会按照 方法执行时间 周期执行。 
  • scheduleWithFixedDelay : 方法执行完毕后,等待 period 时间后,再次执行。

        6、完整的测试代码

public static void main(String[] args) throws ExecutionException, InterruptedException {
        final ScheduledExecutorService executor = Executors.newScheduledThreadPool(3);
        System.out.println(Thread.currentThread().getName()+" === start ," +DateUtils.getDateTime());

        // 1、scheduler ,无返回值测试
//        schedulerNoReturn(executor);

        // 2、scheduler ,有返回值测试
//        final String s = schedulerYesReturn(executor);
//        System.out.println("scheduler ,有返回值测试:"+s);

        // 3、、固定时间执行  expireTime > delay 时,以 period 为准
//        scheduleAtFixedRateTest(executor,4L); // 小于
//        scheduleAtFixedRateTest(executor,5L); // 等于
//        scheduleAtFixedRateTest(executor,6L); // 大于

        // 4、固定时间执行,当前任务执行完毕后,再间隔 delay 秒后执行
//        scheduleWithFixedDelayTest(executor,4L); // 小于
//        scheduleWithFixedDelayTest(executor,5L); // 等于
        scheduleWithFixedDelayTest(executor,6L); // 大于

        System.out.println(Thread.currentThread().getName()+" === end , "+DateUtils.getDateTime());

    }
    

参考资料: Java 多线程 Runnable 与 Callable 接口的区别