写点什么

Java 进阶 (十八)Java 实现定时器 (Timer)

  • 2022 年 9 月 14 日
    上海
  • 本文字数:1526 字

    阅读完需:约 5 分钟

Java进阶(十八)Java实现定时器(Timer)

一、前言

在应用开发中,经常需要一些周期性的操作,比如每 5 分钟执行某一操作等。对于这样的操作最方便、高效的实现方式就是使用java.util.Timer工具类。java.util这个包中可以找到 Timer 和 TimerTask 这两个类。Timer直接从 Object 继承,它相当于一个计时器,能够用它来指定某个时间来执行一项任务,或者每隔一定时间间隔反复执行同一个任务。创建一个 Timer 后,就会生成一个线程在背后运行,来控制任务的执行。而 TimerTask 就是用来实现某项任务的类,它实现了 Runnable 接口,因此相当于一个线程。

二、实现

第一步:编写测试类,该类 extends TimerTask,重新 run()方法,run 方法里面就是你要执行的逻辑代码,示例如下:


import java.text.SimpleDateFormat;import java.util.Date;import java.util.TimerTask;public class MyTest1 extends TimerTask {   private SimpleDateFormat sf=new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"); @Override public void run() {     System.out.println("现在时间是:"+sf.format(new Date())); }}
复制代码


第二步:编写一个类,该类实现 ServletContextListener 接口


import javax.servlet.ServletContextEvent;import javax.servlet.ServletContextListener;public class TimerTaskManager implements ServletContextListener {private Timer timer; @Override public void contextInitialized(ServletContextEvent sce) {  System.out.println("程序定时执行任务.....................................");  MyTest1 t=new MyTest1();  timer=new Timer("开始执行任务",true);/* 执行MyTest1中的run方法,t代表TimerTask的子类,0代表延迟0毫秒执行run方 * 法,1000表示每隔一秒执行一次run方法,后面两个参数可根据自己的需求而定义*/  timer.schedule(t, 0, 1000); } @Override public void contextDestroyed(ServletContextEvent sce) {  System.out.println("程序定时执行任务结束.....................................");  timer.cancel(); }}
复制代码


第三步:在 web.xml 中添加如下代码里面填写 TimerTaskManager 的路径,程序在 web 容器启动后会初始化加载 TimerTaskManager 的 contextInitialized 方法。

三、监听器添加方式

加 listener 标签,listener 里面加 listener-class 标签,listener-class 标签里面内容为 TimerTaskManager 的路径,如:com.TimerTaskManager.

<listener><listener-class>weiming.lmapp.timer.SysContextListener</listener-class></listener>
复制代码

四、注意点分析

1、任务调度要优先考虑实时保证

由于 Java 的天性,并且在开发 JDK 的过程中要考虑到不同平台,而不同平台的线程调度机制是不同的,因此各种平台下 JVM 的线程调度机制也是不一致的。从而Timer不能保证任务在所指定的时间内执行。另外由于TimerTask是实现Runnable接口的,在TimerTask被放进线程队列睡眠一段时间(wait)之后,当到了指定的该唤起该 TimerTask 时,由于执行的确切时机取决于 JVM 的调度策略和当前还有多少线程在等待 CPU 处理。因此就不能保证任务在所指定的时间内执行。通常在如下两种情况下导致任务延迟执行:

(1)有大量线程在等待执行;

(2)GC 机制的影响导致延迟;


这也是为什么在 Timer API 中存在两组调度方法的原因。即:

(1)schedule()

用固定延迟调度。使用本方法时,在任务执行中的每一个延迟会传播到后续的任务的执行。

(2)scheduleAsFixedRate()

用固定比率调度。使用本方法时,所有后续执行根据初始执行的时间进行调度,从而希望减小延迟。

具体使用哪一个方法取决于哪些参数对你的程序或系统更重要。


2、每个 Timer 对象要在后台启动一个线程。

这种性质在一些托管的环境下不推荐使用,比如在应用服务器中。因为这些线程不在容器的控制范围之内了。

发布于: 刚刚阅读数: 5
用户头像

No Silver Bullet 2021.07.09 加入

岂曰无衣 与子同袍

评论

发布
暂无评论
Java进阶(十八)Java实现定时器(Timer)_Java_No Silver Bullet_InfoQ写作社区