java web 定时器用法

来源:互联网 发布:好吃的大米 知乎 编辑:程序博客网 时间:2024/04/27 20:31

在做web开发的时候,经常需要在一定的时间去跟新某些东西,或是加载某些东西,这就用到了定时器。

当Web工程启动时,定时器能自动开始计时,在整个Web工程的生命期里,定时器每过一段时间就执行一次,所以考虑定时器存放的位置。

定时器肯定不能不能简单的存在于单个Servlet或JavaBean中,必须能让定时器宿主的存活期为整个Web工程生命期,在工程启动时能自动加载运行。结合这两点,跟 Servlet上下文有关的侦听器就最合适不过了,通过在工程的配置文件中加以合理配置,会在工程启动时自动运行,并在整个工程生命期中处于监听状态。

下面就Servlet侦听器结合Java定时器来讲述整个实现过程:

import java.util.Timer;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.http.HttpServlet;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
* @date 2010-1-14
* @author wangpeng
* 功能:监听器,用来实现计时器
*/
public class ContextListener extends HttpServlet implements
ServletContextListener {
/**
*
*/
private static final long serialVersionUID = 1L;

private static final Log log = LogFactory.getLog(NewsTimerTask.class);

public ContextListener() {
}

private Timer timer = null;

public void contextInitialized(ServletContextEvent event) {
timer = new Timer(true);
log.info("定时器已启动");
timer.schedule(new NewsTimerTask(event.getServletContext()),
    TIME_NEWS_DELAY, TIME_NEWS_PERIOD);
log.info("已经添加任务调度表");
}

public void contextDestroyed(ServletContextEvent event) {
timer.cancel(); //定时器的销毁
log.info("定时器销毁");
}

}

NewsTimerTask- 所要安排的任务。
TIME_NEWS_DELAY - 执行任务前的延迟时间,单位是毫秒。 为0时表明不延迟
TIME_NEWS_PERIOD - 执行各后续任务之间的时间间隔,单位是毫秒。

NewsTimerTask继承TimerTask
TimerTask是 由 Timer 安排为一次执行或重复执行的任务。

在这里我们把ServletContext传进来,就是为了方面一些存储的操作。我这里举的是调用spring,获取bean

import java.util.List;
import java.util.TimerTask;

import javax.servlet.ServletContext;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;

/**
* @date 2010-1-14
* @author wangpeng
* 功能:计时器
*/
public class NewsTimerTask extends TimerTask {

private static final Log log = LogFactory.getLog(NewsTimerTask.class);

private ServletContext context = null;
private NewsinfoDaoImpl newsinfoDao = null;
private static boolean isRunning = false;
public NewsTimerTask(){}

public NewsTimerTask(ServletContext context) {
this.context = context;
WebApplicationContext wac = WebApplicationContextUtils.getRequiredWebApplicationContext(context);
newsinfoDao = (NewsinfoDaoImpl) wac.getBean("newsinfoDao");
System.out.println("-------------" + newsinfoDao.getById(1).get(0).getContent());
}

@Override
public void run() {
log.info("----------------定时器开始执行-----------------------");
if(!isRunning) {
   isRunning = true;
   List<Newsinfo> listTopNews = newsinfoDao.queryByBake1(ConstantsConsumer.NEW_TOP_YES);
   List<Newsinfo> listTopSystem = newsinfoDao.queryByType(0, ConstantsConsumer.NEWS_SYSTEM);
   context.setAttribute("listTopNews", listTopNews);
   if(listTopSystem.size() > 0) {
    context.setAttribute("newsinfoSystem", listTopSystem.get(0));
   }
   isRunning = false;
} else {
   log.info("上次还在执行中……");
}
log.info("----------------定时器执行结束-----------------------");
}

}

最后在把监听器部署到web中就可以了

<listener>
<listener-class>ContextListener</listener-class> //com.test.xiangmu.ContextListener
</listener>

-------------------------------------------------------------------------------------------------------

Java关于Timer.schedule() 执行定时任务的方法

timer.schedule(new MyTask(),long time1,long timer2);

今天算是彻底的搞懂了这个曾经让我为之头疼的方法。下面我就重点介绍一下:

第一个参数,是 TimerTask 类,在包:import java.util.TimerTask .使用者要继承该类,并实现 public void run() 方法,因为 TimerTask 类 实现了 Runnable 接口。

第二个参数的意思是,当你调用该方法后,该方法必然会调用 TimerTask 类 TimerTask 类 中的 run() 方法,这个参数就是这两者之间的差值,转换成汉语的意思就是说,用户调用 schedule() 方法后,要等待这么长的时间才可以第一次执行 run() 方法。

第三个参数的意思就是,第一次调用之后,从第二次开始每隔多长的时间调用一次 run() 方法。

技术人员在实现内部办公系统与外部网站一体化的时候,最重要的步骤就是从OA系统读取数据,并且根据网站模板生成最终的静态页面。这里就需要一个定时任务,循环的执行。

技术人员在写定时任务的时候,想当然的以为Timer.schedule(TimerTask task, long delay)就是重复的执行task。程序运行后发现只运行了一次,总觉得是task里的代码有问题,花了很长时间调试代码都没有结果。

仔细研读java api,发现:

schedule(TimerTask task, long delay)的注释:Schedules the specified task for execution after the specified delay。大意是在延时delay毫秒后执行task。并没有提到重复执行

schedule(TimerTask task, long delay, long period)的注释:Schedules the specified task for repeated fixed-delay execution, beginning after the specified delay。大意是在延时delay毫秒后重复的执行task,周期是period毫秒。

这样问题就很明确schedule(TimerTask task, long delay)只执行一次,schedule(TimerTask task, long delay, long period)才是重复的执行。关键的问题在于程序员误以为schedule就是重复的执行,而没有仔细的研究API,一方面也是英文能力不够,浏览API的过程中不能很快的理解到含义。