同学在做一个Java web项目时遇到了点麻烦。问题是这样的,他需要在后台运行一些计划任务,通过Timer来实现的。同时又需要通过Servlet来控制指定的计划任务运行或者停止运行。这个问题看似简单,实际上涉及了一些Servlet生命周期的知识以及变量作用域的知识。
首先看Timer应该在什么时候创建。在的doGet()中创建显然是不行的,因为doGet作用在用户访问的那个线程,这里创建的Timer无法通过cancle停止,因为再一次访问Servlet的时候会创建一个新的线程,在这个新的线程中是无法调用之前线程创建的Timer的。所以应该把Timer作为Servlet的一个成员,这样就可以在不同的线程中访问Timer这个示例了。
但是问题又来了,由于有多个计划任务,创建每个计划任务时调用的是同一个Timer实例的schedule()方法,当调用cancle()方法时,所有的计划任务都会撤销。于是我在Servletz中创建了一个Map来将多个Timer与特定的key绑定,为每一个计划任务单独创建一个Timer,这样就可以分别撤销计划任务了。
以下是我写的示例代码:
package sample;
import java.io.IOException;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Timer;
import java.util.TimerTask;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class MyTimer extends HttpServlet {
private static final long serialVersionUID = 1L;
Map map;
public MyTimer() {
super();
map = new HashMap();
}
void setTimer(String key) {
Timer t = new Timer();
map.put(key, t);
}
void removeTimer(String key) {
if (map.containsKey(key)) {
map.get(key).cancel();
map.remove(key);
}
}
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
String s;
String t;
s=request.getParameter("s");
t=request.getParameter("t");
if(s==null || t==null){
response.getWriter().println("Ready");
}else{
if (t.equals("1")) {
setTimer(s);
map.get(s).schedule(new MyTick(s), new Date(), 1000);
response.getWriter().println("timer "+s+" on!");
} else {
removeTimer(s);
response.getWriter().println("timer "+s+" off!");
}
}
if(!map.isEmpty()){
for(String k:map.keySet()){
response.getWriter().println(k+" is running");
}
}
}
protected void doPost(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
}
}
class MyTick extends TimerTask {
boolean isRun = false;
String id;
MyTick(String id) {
super();
this.id = id;
}
public void run() {
if (!isRun) {
isRun = true;
System.out.println(this.id + ":" + (new Date().toString()));
isRun = false;
}
}
}
在服务器上运行这个servlet,在浏览器中访问“http://path-to/servlet?t=a&s=1”,可以看到命令行中看到计时器a在运行,再输入“http://path-to/servlet?t=b&s=1”,可以看到计时器a和b同时在运行,然后访问“http://path-to/servlet?t=a&s=0”,可以看到计时器a停止运行。
至此,这个问题已经得到解决。
顶
嘿嘿@tigras