这些天,一直在做一个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()中的值
怎么办呢?新建一个线程类,它又取不到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秒
再登陆几次
现在是登陆了5次
强制关掉服务器(这样它没有机会调用destroy方法了),果然把访问量保存到文本中了
重启浏览器,再登录,果然是6次
如果你用Tomcat 6.0版本,还是会出问题,原因就是当你正常关掉服务器时,线程还在运行,这样,线程就取不到ServletContext的值,
Tomcat 7.0的版本我测试过没有这种问题,所以最好加上这句,就是主线程结束,后台线程也结束,就什么问题都没有了(想了好久才想到这个方法)
Al thread = new Al();
thread.setDaemon(true); //后台线程
thread.start();
这样,线程就可以每隔一段时间,自动保存访问量了,解决自己的难题,真的很开心啊
- 大小: 10.9 KB
- 大小: 46.1 KB
- 大小: 57.2 KB
- 大小: 6.7 KB
- 大小: 42.9 KB
分享到:
相关推荐
由于Servlet实例默认是多线程的,因此在编写Servlet时需要注意线程安全问题。例如,避免在Servlet实例中使用非线程安全的全局变量。 7. **Servlet的异步处理**: 自Java Servlet 3.0版本开始,Servlet支持异步...
它使用多线程模型来服务多个请求,并实现了ServletConfig接口,允许Servlet获取配置信息。 3. **HttpServlet类** HttpServlet是GenericServlet的子类,专门为处理HTTP协议请求而设计。它重写了`service()`方法,...
从Servlet 3.0开始,引入了注解配置,可以使用`@WebServlet`直接在Servlet类上声明,减少了对web.xml的依赖。 10. **AsyncServlet**: Servlet 3.0还引入了异步处理能力,允许Servlet在`service()`方法内部启动一...
在Java中,多线程的实现主要通过两种方式:继承Thread类和实现Runnable接口。下面我们将深入探讨多线程在客户端和服务器端的应用以及如何在Java中创建和管理线程。 1. **线程基础** - **线程与进程**:线程是进程...
6. **多线程模型**:Servlet容器通常为每个请求创建一个新的线程,因此Servlet必须是线程安全的。开发者需要注意避免在Servlet实例中使用非线程安全的变量。 7. **异步处理**:从Servlet 3.0版本开始,引入了异步...
9. **多线程**:Servlet默认是线程安全的,一个Servlet实例可以服务于多个并发请求。开发者需要注意同步问题,避免在Servlet中使用静态变量存储请求相关数据。 10. **过滤器(Filter)**:Servlet API还提供了过滤...
Servlet容器会自动处理多线程问题,因为一个Servlet实例可能会服务于多个并发请求。 接下来,我们将探讨Servlet配置和部署。在`web.xml`部署描述符文件中,可以定义Servlet的映射、初始化参数和监听器。Servlet映射...
同时,使用同步块或锁来保护共享资源是保证多线程环境下正确性的关键。 在Servlet中,转发和重定向是两种常见的导航方式。转发是在服务器端完成的,请求被传递给另一个资源,客户端浏览器并不知道这个过程;而...
3. **多线程安全**:Servlet默认是线程安全的,意味着服务器可能会并发地调用同一个Servlet实例的`service()`方法。因此,开发者需要确保在Servlet中不使用非线程安全的成员变量。 4. **Servlet容器**:如Tomcat,...
3. **Java特性**:Servlet继承了Java的所有优点,如垃圾回收、多线程、面向对象等,可以方便地利用Java丰富的库。 4. **可扩展性**:Servlet可以利用Servlet容器(如Tomcat、Jetty等)提供的特性,如过滤器、监听器...
"一个servlet类处理多个请求(反射优化)"的主题正是解决这一问题的一种策略,通过反射技术优化Servlet的性能,提高其复用性。 反射是Java编程语言的一个强大特性,它允许程序在运行时检查和修改自身的结构和行为。...
若Servlet内部有共享数据,需使用同步机制,避免数据冲突。 六、Filter与Listener Servlet学习中,Filter和Listener也是重要组成部分。Filter用于拦截请求和响应,可以实现如登录验证、字符编码转换等功能。...
3. **多线程处理**:Servlet容器通常会为每个请求创建一个新的线程,查看源码能帮助理解多线程环境下的Servlet处理。 4. **会话管理**:研究`HttpSession`接口,理解如何存储和检索会话数据,以及会话超时和失效的...
由于Servlet是多线程的,同一个Servlet实例可能会服务于多个请求。因此,开发者需要注意线程安全问题,避免在Servlet中使用全局变量。 七、Servlet的会话管理 通过HttpServletRequest的getSession()方法,Servlet...
这提高了服务器处理高并发的能力,避免了传统的多线程模型中线程池资源的浪费。通过`ServletRequest.startAsync()`方法,开发者可以启动一个异步上下文,并在后续时间点调用`AsyncContext.complete()`来结束处理。 ...
- `test-servlet3-without-webxml`这个项目可能包含一个或多个使用了`@WebServlet`注解的Servlet类,以及相关的测试代码,用于演示如何在没有`web.xml`的情况下运行Servlet 3.0应用。 6. **运行与部署** - 使用...
在实际开发中,常常使用Servlet来处理请求,调用JavaBean(Java类,封装业务逻辑)进行业务处理,然后通过`forward()`或`include()`方法将控制权交给JSP,由JSP生成最终的HTML响应给客户端。这种模式符合MVC(Model-...
8. **过滤器链的改进**:Servlet 3.0允许在同一个Filter中匹配多个URL模式,过滤器链的控制也更加灵活,可以使用`doFilter(ServletRequest, ServletResponse, FilterChain)`方法的参数控制过滤器执行流程。...