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() + "\tA"); }, 1, TimeUnit.SECONDS);
// 立即执行,然后每秒执行一次,注重次数
stpe.scheduleAtFixedRate(() -> { System.out.println(Thread.currentThread().getName() + "\tB"); }, 0, 1, TimeUnit.SECONDS);
// 立即执行,然后每两秒执行一次,注重间隔时间
stpe.scheduleWithFixedDelay(() -> { System.out.println(Thread.currentThread().getName() + "\tC"); }, 0, 2, TimeUnit.SECONDS);

Thread.sleep(10000);
stpe.purge();
// 关闭
stpe.shutdown();

猜你喜欢

转载自www.cnblogs.com/jhxxb/p/10877469.html