`

Servlet线程安全问题

 
阅读更多

测试Servlet是否线程安全

测试代码

package com.servlet.study;

import java.io.IOException;

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


public class ThreadSafeTestServlet extends HttpServlet{

	/**
	 * 
	 */
	private static final long serialVersionUID = -5678315968996207090L;
	
	private String name;
	
	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		resp.setContentType("text/html");
		resp.setCharacterEncoding("utf-8");
		// TODO Auto-generated method stub
		System.out.println(this+":"+Thread.currentThread());
		name = req.getParameter("user");
		try {
			Thread.sleep(2000);
		} catch (InterruptedException e1) {
			// TODO Auto-generated catch block
		}
		resp.getWriter().println("用户名:"+name);;
		System.out.println("Counter = "+name);
	}
	
	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		// TODO Auto-generated method stub
		doPost(req, resp);
	}
	
}

 

页面请求:

请求1:http://localhost:8080/TESTWeb/thread?user=lisi

请求2:http://localhost:8080/TESTWeb/thread?user=wangw 

输出结果:

com.servlet.study.ThreadSafeTestServlet@5dcc783c:Thread[http-nio-8080-exec-27,5,main]

com.servlet.study.ThreadSafeTestServlet@5dcc783c:Thread[http-nio-8080-exec-24,5,main]

Counter = wangw

Counter = wangw

 请求1的输出,被请求2的name改写了,用户lisi的页面显示wangw的信息。

结论:

1、Servlet对象是一个无状态的单例对象(Singleton),因为请求多次,打印出来的hashcode值都相同。

2、Servlet在不同的线程池中运行,如上的Thread[http-nio-8080-exec-27和 24 区分出不同的线程执行了同一段Servlet逻辑代码。

3、name变量在不同的线程中共享,且它的值被不同的线程修改。输出时,已被其它线程修改后的值。

也就是说,其它线程会篡改当前线程中实例变量的值,针对这些对象的访问不是线程安全的。

 

解决方式一:

使用局部变量,代替全局变量。

package com.servlet.study;

import java.io.IOException;

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


public class ThreadSafeTestServlet extends HttpServlet{

	/**
	 * 
	 */
	private static final long serialVersionUID = -5678315968996207090L;
	
	
	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		String name;
		resp.setContentType("text/html");
		resp.setCharacterEncoding("utf-8");
		// TODO Auto-generated method stub
		System.out.println(this+":"+Thread.currentThread());
		name = req.getParameter("user");
		try {
			Thread.sleep(2000);
		} catch (InterruptedException e1) {
			// TODO Auto-generated catch block
		}
		resp.getWriter().println("用户名:"+name);;
		System.out.println("Counter = "+name);
	}
	
	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		// TODO Auto-generated method stub
		doPost(req, resp);
	}
	
}

 

输出:

com.servlet.study.ThreadSafeTestServlet@53a2686d:Thread[http-nio-8080-exec-44,5,main]

com.servlet.study.ThreadSafeTestServlet@53a2686d:Thread[http-nio-8080-exec-39,5,main]

Counter = wangw

Counter = lisi

 

 

解决方式二:

使用synchorized关键字,保证一次只有一个线程访问保护的区域块。

private String name;
	
	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		resp.setContentType("text/html");
		resp.setCharacterEncoding("utf-8");
		// TODO Auto-generated method stub
		System.out.println(this+":"+Thread.currentThread());
		synchronized(this){
			
			name = req.getParameter("user");
			try {
				Thread.sleep(2000);
			} catch (InterruptedException e1) {
				// TODO Auto-generated catch block
			}
			resp.getWriter().println("用户名:"+name);;
			System.out.println("Counter = "+name);
		}
	}

页面请求:

http://localhost:8080/TESTWeb/thread?user=lisi

http://localhost:8080/TESTWeb/thread?user=wangw 

输出结果:

信息: Reloading Context with name [/TESTWeb] is completed

com.servlet.study.ThreadSafeTestServlet@3fadc5ba:Thread[http-nio-8080-exec-8,5,main]

com.servlet.study.ThreadSafeTestServlet@3fadc5ba:Thread[http-nio-8080-exec-4,5,main]

Counter = wangw

Counter = lisi

 

 

 

分享到:
评论

相关推荐

    servlet线程安全问题

    servlet线程安全问题servlet线程安全问题

    Servlet线程安全问题.docx

    Servlet是线程不安全的。Servlet体系是建立在java多线程的基础之上的,它的生命周期是由Tomcat 来维护的。当客户端第一次请求Servlet的时候,tomcat会根据web.xml配置文件实例化servlet, 当又有一个客户端访问该...

    深入研究Servlet线程安全性问题

    深入研究Servlet线程安全性问题...

    servlet与Struts action线程安全问题分析

    servlet与Struts action线程安全问题分析

    深入研究Servlet线程安全性问题.pdf

    比较深刻地论述了Servlet线程安全性问题

    servlet与Struts action线程安全问题分析(pdf)

    servlet与Struts action线程安全问题分析 <br>===================================================== Servlet的线程安全问题只有在大量的并发访问时才会显现出来,并且很难发现,因此在编写Servlet程序时要...

    Servlet线程安全的解决方法

    当两个或多个线程同时访问同一个Servlet时,可能会发生多个线程同时访问同一资源的情况,数据可能会变得不一致,所以就很容易造成一系列的一些安全性问题。

    Servlet是线程不安全的1

    先从Servlet的工作原理说起:首先简单解释一下Servlet接收和响应客户请求的过程,首先客户发送一个请求,Servlet是调用service()方法对请求

    Servlet网上售票问题引发线程安全问题的思考

    主要是关于Servlet模拟网上售票问题,引发的线程安全问题的思考,感兴趣的小伙伴们可以参考一下

    Java学习笔记-个人整理的

    {8.1}线程的常用属性与方法}{121}{section.8.1} {8.2}后台线程}{123}{section.8.2} {8.3}创建线程的两种方法}{123}{section.8.3} {8.4}Runnable}{123}{section.8.4} {8.5}Sleep阻塞与打断唤醒}{124}{section....

    JSP和Servlet面试题

    6.如何处理Servlet的线程不安全问题 1.最简单的就是不使用字段变量, 2.使用final修饰变量, 3.线程安全就是多线程操作同一个对象不会有问题,线程同步一般来保护线程安全, 所以可以在Servlet的线程里面加上同步...

    Java web中servlet学习笔记 核心

    Java web中servlet学习笔记 核心。servlet执行过程、servlet生命周期、继承类、创建servlet、servlet线程安全、配置信息

    servlet 模拟

    想简单模拟下servlet,看下什么是线程安全,现在发现自己写的程序问题了,果然线程不安全。

    培训资料_servlet

    1、Servlet基本概念 2、Servlet基本运用、配置 3、Servlet生命周期 4、Servlet线程安全 5、Model2与MVC设计模式 6、过滤器 7、分页 8、上传组件SmartUpload 9、监听器 10、配置Tomcat连接池 11、实用技术

    java-servlet-api.doc

    在多线程的环境下,Servlet必须能处理许多同时发生的请求。例外的情况是这个Servlet执行了SingleThreadModel接口,如果是那样的话,Servlet只能同时处理一个请求。 Servlet依照Servlet引擎的映射来响应客户端的请求...

Global site tag (gtag.js) - Google Analytics