• Java-定时任务


    一、 使用 while(true) 和 sleep 实现

    new Thread(){
        @Override
        public void run() {
            while (true) {
                System.out.println("Hello!");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }
    }.start();

    二、使用 Timer 和 TimerTask 实现

    /**
     * 一个 Timer 对应一个线程,用于执行任务
     * @param name 线程名字
     * @param isDaemon 是否为当前线程的守护线程
     */
    Timer timer = new Timer("haha", false);
    
    // 一个 TimerTask 对应一个任务
    TimerTask task1 = new TimerTask() {
        @Override
        public void run() {
            System.out.println(Thread.currentThread().getName() + "Hello! A");
        }
    };
    // 立即执行,只执行一次
    timer.schedule(task1, 0);
    timer.schedule(task1, 0, 1000);
    
    TimerTask task2 = new TimerTask() {
        @Override
        public void run() {
            System.out.println(Thread.currentThread().getName() + "Hello! B");
        }
    };
    // 立即执行,然后每秒执行一次
    timer.scheduleAtFixedRate(task2, 0, 1000);
    
    Thread.sleep(5000);
    // 取消任务
    task2.cancel();
    
    Thread.sleep(5000);
    // 将所有已经取消的任务移除(释放资源)
    timer.purge();
    // 停止 timer 中的所有任务,并终止计时器,无法再提交任务
    timer.cancel();

    schedule 与 scheduleAtFixedRate 区别

    schedule 注重间隔时间,不管任务执行需要多长时间,下一次执行都是在执行完成后的指定间隔时间再执行。

    scheduleAtFixedRate 注重执行次数,例如当任务太多或其他原因导致某段时间内执行次数不够(总时间/间隔时间),则会尝试缩短间隔时间,保证总体执行次数。

    三、使用 ScheduledThreadPoolExecutor 实现

    阿里巴巴 Java 手册中的片段

    多线程并行处理定时任务时,Timer 运行多个 TimeTask 时,只要其中之一没有捕获抛出的异常,其它任务便会自动终止运行,使用 ScheduledExecutorService 则没有这个问题。
    
    线程池不允许使用 Executors 去创建,而是通过 ThreadPoolExecutor 的方式,这样的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。
    说明:Executors 返回的线程池对象的弊端如下:
    1)FixedThreadPool 和 SingleThreadPool:
    允许的请求队列长度为 Integer.MAX_VALUE,可能会堆积大量的请求,从而导致 OOM。
    2)CachedThreadPool 和 ScheduledThreadPool:
    允许的创建线程数量为 Integer.MAX_VALUE,可能会创建大量的线程,从而导致 OOM。

    说明了创建线程池的规范,以及使用 Timer 的问题

    // Guava 库的工具类,线程工厂,这里主要用来设置线程名字
    ThreadFactory namedThreadFactory = new ThreadFactoryBuilder().setNameFormat("demo-pool-%d").build();
    ScheduledThreadPoolExecutor stpe = new ScheduledThreadPoolExecutor(10, namedThreadFactory, new ThreadPoolExecutor.AbortPolicy());
    
    // 一秒后执行
    stpe.schedule(() -> { System.out.println(Thread.currentThread().getName() + "	A"); }, 1, TimeUnit.SECONDS);
    // 立即执行,然后每秒执行一次,注重次数
    stpe.scheduleAtFixedRate(() -> { System.out.println(Thread.currentThread().getName() + "	B"); }, 0, 1, TimeUnit.SECONDS);
    // 立即执行,然后每两秒执行一次,注重间隔时间
    stpe.scheduleWithFixedDelay(() -> { System.out.println(Thread.currentThread().getName() + "	C"); }, 0, 2, TimeUnit.SECONDS);
    
    Thread.sleep(10000);
    stpe.purge();
    // 关闭
    stpe.shutdown();
  • 相关阅读:
    关于sizeof,对空指针sizeof(*p)可以吗?
    Mysql之锁(一)
    Mysql之事务
    Mysql之Explain关键字及常见的优化手段
    Mysql查询优化器之关于子查询的优化
    Mysql查询优化器之关于JOIN的优化
    Mysql查询优化器之基本优化
    Mysql之B+树索引实战
    Mysql之索引
    Mysql之InnoDB行格式、数据页结构
  • 原文地址:https://www.cnblogs.com/jhxxb/p/10877469.html
Copyright © 2020-2023  润新知