@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