• jdk定时任务的使用


    Timer

    JDK内置了 java.util.Timer 类,

    可以用来调度 java.util.TimerTask 任务。

    可以前端页面传递定时执行的简单时间

    几个重要的方法:

    schedule:开始调度任务,提供了几个包装方法;
    cancle:终止任务调度,取消当前调度的所有任务,正在运行的任务不受影响;
    purge:从任务队列中移除所有已取消的任务;
    另外,java.util.TimerTask 就是实现了 Runnable 接口,具体任务逻辑则是在 run 方法里去实现。

    private static void timerTask() throws InterruptedException {
            Timer timer = new Timer();
    
            TimerTask timerTask = new TimerTask() {
                @Override
                public void run() {
                    System.out.println("hi, 欢迎关注:Java技术栈");
                }
            };
    
            // 第一次任务延迟时间
            long delay = 2000;
    
            // 任务执行频率
            long period = 3 * 1000;
    
            // 开始调度
            timer.schedule(timerTask, delay, period);
    
            // 指定首次运行时间
    // timer.schedule(timerTask, DateUtils.addSeconds(new Date(), 5), period);
    
            Thread.sleep(20000);
    
            // 终止并移除任务
            timer.cancel();
            timer.purge();
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    这种实现方式比较简单,可以指定首次执行的延迟时间、首次执行的具体日期时间,以及执行频率,能满足日常需要。

    另外,需要注意的是,Timer 是线程安全的,因为背后是单线程在执行所有任务。

    Timer 也会有一些缺陷:

    Timer 是单线程的,假如有任务 A,B,C,任务 A 如果执行时间比较长,那么就会影响任务 B,C 的启动和执行时间,如果 B,C 执行时间也比较长,那就会相互影响;
    Timer 不会捕获异常,如果 A,B,C 任何一个任务在执行过程中发生异常,就会导致 TImer 整个定时任务停止工作;
    Timer 是基于绝对时间调度的,而不是基于相对时间,所以它对系统时间的改变非常敏感;
    所以,如果在使用 Timer 的过程中要注意这些缺陷,虽然可以用,但不推荐。

    ScheduledExecutorService

    因 Timer 有一些缺陷,所以不太建议使用 Timer,推荐使用 ScheduledExecutorService:

    /**
     * Creates a thread pool that can schedule commands to run after a
     * given delay, or to execute periodically.
     * @param corePoolSize the number of threads to keep in the pool,
     * even if they are idle
     * @return a newly created scheduled thread pool
     * @throws IllegalArgumentException if {@code corePoolSize < 0}
     */
    public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
        return new ScheduledThreadPoolExecutor(corePoolSize);
    }
    
    /**
     * Creates a thread pool that can schedule commands to run after a
     * given delay, or to execute periodically.
     * @param corePoolSize the number of threads to keep in the pool,
     * even if they are idle
     * @param threadFactory the factory to use when the executor
     * creates a new thread
     * @return a newly created scheduled thread pool
     * @throws IllegalArgumentException if {@code corePoolSize < 0}
     * @throws NullPointerException if threadFactory is null
     */
    public static ScheduledExecutorService newScheduledThreadPool(
            int corePoolSize, ThreadFactory threadFactory) {
        return new ScheduledThreadPoolExecutor(corePoolSize, threadFactory);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    上了线程池,每个调度任务都会分配到线程池中的某一个线程去执行,任务就是并发调度执行的,任务之间互不影响。

    几个重要的调度方法:

    schedule:只执行一次调度;
    scheduleAtFixedRate:按固定频率调度,如果执行时间过长,下一次调度会延迟,不会同时执行;
    scheduleWithFixedDelay:延迟调度,上一次执行完再加上延迟时间后执行;
    另外,可以看出,任务是支持 Runnable 和 Callable 调度的。

    /**
     * 线程池定时任务
     * 这是一个按固定频率调度的任务,创建了 10 个核心线程数,首次执行延迟 2 秒,后续每 3 秒执行一次。
     * 这种方式简单、好用,避免了使用 Timer 带来的各种问题,推荐使用这种实现方式。
     */
     public static void poolTask(){
            ScheduledExecutorService pool = Executors.newScheduledThreadPool(10);
    
            pool.scheduleAtFixedRate(() -> {
                System.out.println("2 秒后开始执行,每 3 秒执行一次");
            }, 2000, 3000, TimeUnit.MILLISECONDS);
    
            pool.schedule(() -> {
                System.out.println("2 秒后开始执行,我只执行一次");
            }, 2000, TimeUnit.MILLISECONDS);
    
            pool.scheduleWithFixedDelay(() -> {
                System.out.println("hi?????");
            }, 2000, 3000,TimeUnit.MILLISECONDS);
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
  • 相关阅读:
    美团面试官:高并发、任务执行时间短的业务怎样使用线程池?
    (55、56)性能分析命令
    revolution slider 6 里面如何设置幻灯片自动播放及播放速度
    针对Java、C++和Python语言的单元测试工具,你最喜欢哪一个?
    D. For Gamers. By Gamers.(思维 + dp + 二分)(调和级数)
    Go 之 gotable 格式化打印表格
    javaWeb使用spring框架时在配置上的编程技巧
    Linux驱动开发 数据的传输和辅助信息的作用
    [常用工具] Python视频处理库VidGear使用指北
    智源发布最强开源可商用中英文语义向量模型 BGE,超越同类模型,解决大模型制约问题
  • 原文地址:https://blog.csdn.net/qq_44779847/article/details/133378470