@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();

https://blog.csdn.net/f641385712/article/details/105270194

https://blog.csdn.net/f641385712/article/details/83717639