Servlet用内部类加载多线程

这些天,一直在做一个web小项目,也就是练习一下Servlet,昨晚,想在网站中增加一个统计访问量的功能,因为考虑到用多线程每隔一定的时间去自动的保存访问量,会更准确(因为,你不用隔一段去保存访问量,如果突然断电了,访问量就会失去了),想法是好的,但做起来,还真的不容易:

以下程序是没有加载线程
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class InitServlet extends HttpServlet {


/**
* 关掉服务器时,会执行这个函数
*/
public void destroy() {
this.Thread_Init();
}

public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {

response.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8");
PrintWriter out = response.getWriter();

out.println("</HTML>");

}

public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {

this.doGet(request, response);
}

private void Thread_Init()

{
System.out.println("thread调用");

String FilePath = this.getServletContext().getRealPath("Nums.text");

try {
FileWriter fileReader = new FileWriter(FilePath);
BufferedWriter buffer = new BufferedWriter(fileReader);
// 从ServletContext中读取数据
String nums = (String) this.getServletContext()
.getAttribute("nums");
// 把数据存到文本中
buffer.write(nums);

buffer.close();
fileReader.close();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {

}
}

/**
* Initialization of the servlet. <br>
*
* @throws 初始化会先调用这个函数
*/
public void init() throws ServletException {
System.out.println("第一次调用");
String FilePath = this.getServletContext().getRealPath("Nums.text");

try {
FileReader fileReader = new FileReader(FilePath);
BufferedReader buffer = new BufferedReader(fileReader);
String num = buffer.readLine();
// 把数据存到ServletContext中
this.getServletContext().setAttribute("nums", num);
System.out.println("num=" + num);
buffer.close();
fileReader.close();
} catch (Exception e) {
e.printStackTrace();
} finally {

}
}

}

我用了Runnable的线程接口
public class InitServlet extends HttpServlet implements Runnable{ }
在 public void init() throws ServletException {}方法中增加了:
InitServlet tmp = new InitServlet();
Thread al = new Thread(tmp);
al.start();

在Run中增加了以下代码,测试吗,就5秒钟保存一次结果
public void run() {
int u = 0;
while (true) {
u++;
try {
Thread.sleep(5000);
System.out.println("你运行了"+u+"次");
this.Thread_Init();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}

}

}

运行结果是它只运行一次,就不动了,也不报错,估计是取不到ServletContext()中的值


[img]http://dl2.iteye.com/upload/attachment/0103/1662/408b82c7-83f6-3f42-a7c0-2ef5cd913888.jpg[/img]

怎么办呢?新建一个线程类,它又取不到ServletContext,用构造函数传过来,也麻烦,突然间,我想到了内部类,用内部类是不是,可以解决呢,试一下再说:
public void init() throws ServletException {
System.out.println("第一次调用");
String FilePath = this.getServletContext().getRealPath("Nums.text");

try {
FileReader fileReader = new FileReader(FilePath);
BufferedReader buffer = new BufferedReader(fileReader);
String num = buffer.readLine();
this.getServletContext().setAttribute("nums", num);
System.out.println("num=" + num);
buffer.close();
fileReader.close();

class Al extends Thread{
public void run() {
int u = 0;
while (true) {
synchronized (this) {
u++;
try {
System.out.println("第" + u + "秒");
Thread.sleep(5000);
Thread_Init();
} catch (Exception e) {
e.printStackTrace();
}

}

}
}
}

Al thread = new Al();
thread.start();


} catch (Exception e) {
e.printStackTrace();
} finally {

}
}

运行一下,果然可以
信息: Server startup in 3218 ms
thread调用
第2秒
thread调用
第3秒
thread调用
第4秒
thread调用
第5秒
id= 1 password= 123
++++++++++++++++++++++
thread调用
第6秒
thread调用
第7秒
id= 1 password= 123
++++++++++++++++++++++
thread调用
第8秒

再登陆几次

[img]http://dl2.iteye.com/upload/attachment/0103/1666/e4b8b158-5001-3803-a1e3-ebce19b77b6c.jpg[/img]

现在是登陆了5次

[img]http://dl2.iteye.com/upload/attachment/0103/1670/08bb0197-7cbd-3ac7-a73c-e39d63552eba.jpg[/img]

强制关掉服务器(这样它没有机会调用destroy方法了),果然把访问量保存到文本中了


[img]http://dl2.iteye.com/upload/attachment/0103/1674/018e9a58-715e-3f49-ac3c-4f40796c09ce.jpg[/img]

重启浏览器,再登录,果然是6次

[img]http://dl2.iteye.com/upload/attachment/0103/1676/dc849c7f-7971-3f7c-b554-1fa1f5ee6ab4.jpg[/img]

如果你用Tomcat 6.0版本,还是会出问题,原因就是当你正常关掉服务器时,线程还在运行,这样,线程就取不到ServletContext的值,
Tomcat 7.0的版本我测试过没有这种问题,所以最好加上这句,就是主线程结束,后台线程也结束,就什么问题都没有了(想了好久才想到这个方法)
Al thread = new Al();
thread.setDaemon(true); //后台线程
thread.start();
这样,线程就可以每隔一段时间,自动保存访问量了,解决自己的难题,真的很开心啊 :D
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值