码迷,mamicode.com
首页 > 编程语言 > 详细

关于Servlet线程安全的问题

时间:2020-02-02 23:38:58      阅读:123      评论:0      收藏:0      [点我收藏+]

标签:容器   request   实例变量   只读   i++   amp   方法   code   除了   

1、多线程Servlet模型--单实例多线程的模式

默认情况下servlet对声明的servlet,只创建一个servlet实例,多个客户访问这个servlet那么servlet容器采取多线程方式。

多个客户同事请求同一个servlet,那么会有多个线程同时执行这个servlet实例的service方法,servlet容器采取的就是单实例多线程的模式,节省了servlet实例的创建,但是引发的并发问题。

2、servlet的线程安全

2.1变量的线程安全

2.1.1避免全局变量

1 public class HelloWorldServlet extends HttpServlet{
 2     private String userName;    
 3     protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException
 4     {
 5         userName=request.getParameter("userName");
 6         PrintWriter out=response.getWriter();
 7         if(userName!=null&&userName!="")
 8         {
 9             out.print(userName);
10         }
11         else {
12             out.println("用户名不存在");
13         }
14     }
15 }

上面的userName为全局变量,多线程调用时会有问题,将变量生命正在方法内(局部变量),每个线程执行方法时重新实例化userName,这样就不会有问题了。

如果是静态资源可以添加final修饰,表示不可变

2.2属性的安全

servlet中可以访问保存在servletContent,httpSession,ServletRequest对象中的属性,这三种对象都提供了getAttribute(),setAttribute()方法用来设置获取属性值,那么这三个对象是否是线程安全?

2.2.1servletContent

首先servletContent是被应用程序下所有的servlet共享的,多个servlet对servletContent同时进行设置和访问,就会出现线程并发问题。

//代码一 
1 protected void service(HttpServletRequest request, HttpServletResponse response)
 2     {
 3         String userName=request.getParameter("userName");
 4         if ("login") {
 5             List list=(List)getServletContext().getAttribute("userList");
 6             list.add(userName);
 7         }
 8         else {
 9             List list=(List)getServletContext().getAttribute("userList");
10             list.remove(userName);
11         }
12     }
//代码二
 1 protected void service(HttpServletRequest request, HttpServletResponse response) throws IOException
 2     {
 3         List list=(List)getServletContext().getAttribute("userList");
 4         int count=list.size();
 5         for(int i=0;i<count;i++)
 6         {
 7             PrintWriter out=response.getWriter();
 8             out.println(list.get(i));
 9         }
10     }

两个请求并发,当线程一执行到代码二第5行时,此时count=5,但是线程二此时执行代码一第10行,删除了一个数据,当线程一再执行就会出现数组越界的问题,怎么解决此类问题呢,第一就是把servletContent拷贝保存起来,第二种就是使用synchronized进行同步(效率低)

2.2.2  httpSession

httpSession是在用户会话中存在的,不像ServletContent是所有的用户共享的,所有说一个httpSession同一时刻只能有同一个用户进行请求,理论上看起来是线程安全的,其实并不是,这和浏览器有关系,同一个浏览器只能具有一个session,如果同一个用户在两个浏览器窗口同时请求,同样会出现线程安全的问题。

2.2.3httpRequest

httpRequest是线程安全的,应为每个线程都会调用service,都会创建一个新的httpRequest,和局部变量一样。

3:SingleThreadModel
从名字很好理解,就是单线程模式,也就是说如果Servlet实现了SingleThreadModel接口,Servlet容器就保证一个时刻只有一个线程在Servlet实例的Service方法运行(其实和同步差不多)这样一来就很影响效率了,现在SingleThreadModel已经被废弃了,值得注意的是就算Servlet实现了SingleThreadModel接口并不一定保证线程安全,比喻上面说的ServletContext,HttpSession,因为ServletContext是应用程序共享的,可能2个Servlet实例同时运行造成线程安全,HttpSession因为是在同一浏览器共享的所以也会出现(虽然可能性很小)
4:总结
1:只要我们了解Servlet容器工作的模式,可能就能够理解为什么Servlet会出现线程安全问题,所以一定牢记Servlet容器是多线程单实例的模型
2:避免使用全局变量,最好是使用局部变量,其实这本身也是一个好的编程习惯
3:应该使用只读的实例变量和静态变量(就是前面加上final意为不可改变)
4:不要在Servlet上自己创建线程,因为Servlet容器已经帮我们做好了。
5:如果要修改共享对象的时候记得要同步,尽量缩小同步的范围(比喻修改Session时候直接使用synchronized(Session)即可),避免影响性能

 

关于Servlet线程安全的问题

标签:容器   request   实例变量   只读   i++   amp   方法   code   除了   

原文地址:https://www.cnblogs.com/zhang19925/p/12253983.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!