Servlet的线程安全

Servlet的线程安全

1、什么是Servlet的线程安全

  1.在Servlet的整个生命周期中,构造方法只被执行一次。也就是说,在Servlet的整个生命周期中,只存在一个Servlet实例对象。这说明Servlet是单例多线程的,可能会引发线程安全问题。java

所谓线程安全就是一个Servlet实例对象会同时处理多个请求,这样的Servlet工做效率的确很高。但若是Servlet中包含成员变量的话,可能一个线程对该成员变量进行写操做,而另外一个线程对该成员变量进行读操做。因此,单例多线程的Servlet不能建立成员变量。浏览器

  下面我将经过例子讨论线程安全问题(不存在线程安全问题的代码:)安全

 1 package gacl.servlet.study;
 2 
 3 import java.io.IOException;
 4 
 5 import javax.servlet.ServletException;
 6 import javax.servlet.http.HttpServlet;
 7 import javax.servlet.http.HttpServletRequest;
 8 import javax.servlet.http.HttpServletResponse;
 9   
10         /**
11          * 当多线程并发访问这个方法里面的代码时,会存在线程安全问题吗??
12          * i变量被多个线程并发访问,可是没有线程安全问题,由于i是doGet方法里面的局部变量,
13          * 当有多个线程并发访问doGet方法时,每个线程里面都有本身的i变量,
14          * 各个线程操做的都是本身的i变量,因此不存在线程安全问题
15          * 多线程并发访问某一个方法的时候,若是在方法内部定义了一些资源(变量,集合等)
16          * 那么每个线程都有这些东西,因此就不存在线程安全问题了
17          */
18 public class ServletThread extends HttpServlet {
19 
20     
21     public void doGet(HttpServletRequest request, HttpServletResponse response)
22             throws ServletException, IOException {
23         int a=1;
24         a++;
25         response.getWriter().write(a);
26     }
27 
28     public void doPost(HttpServletRequest request, HttpServletResponse response)
29             throws ServletException, IOException {
30         doGet(request, response);
31     }
32 
33 }

存在线程安全问题的代码:多线程

 1 package gacl.servlet.study;
 2 
 3 import java.io.IOException;
 4 
 5 import javax.servlet.ServletException;
 6 import javax.servlet.http.HttpServlet;
 7 import javax.servlet.http.HttpServletRequest;
 8 import javax.servlet.http.HttpServletResponse;
 9 
10 public class ServletTreadDemo extends HttpServlet {
11 
12     int i=1;
13     public void doGet(HttpServletRequest request, HttpServletResponse response)
14             throws ServletException, IOException {
15         i++;
16         try {
17             Thread.sleep(1000*3);
18         } catch (InterruptedException e) {
19             e.printStackTrace();
20         }
21         response.getWriter().write(i+"");
22     }
23 
24     public void doPost(HttpServletRequest request, HttpServletResponse response)
25             throws ServletException, IOException {
26         doGet(request, response);
27     }
28 
29 }

把i定义成全局变量,多个线程并发访问变量全局变量 i 时,就会存在线程安全问题了,若是同时开启两个浏览器模拟并发访问同一个Servlet,原本正常来讲,第一个浏览器应该看到2,而第二个浏览器应该看到3的,结果两个浏览器都看到了3。并发

2.线程安全问题的解决办法:

1.加锁(synchronized)this

  加了synchronized后,并发访问i时就不存在线程安全问题了,为何加了synchronized后就没有线程安全问题了呢?假如如今有一个线程访问Servlet对象,那么它就先拿到了Servlet对象的那把锁等到它执行完以后才会把锁还给Servlet对象,因为是它先拿到了Servlet对象的那把锁,因此当有别的线程来访问这个Servlet对象时,因为锁已经被以前的线程拿走了,后面的线程只能排队等候了。。这样不科学。。若是有1000人同时访问ServletThreadDemo1。后面的人还不等得得吐血!!spa

 1 package gacl.servlet.study;
 2 
 3 import java.io.IOException;
 4 
 5 import javax.servlet.ServletException;
 6 import javax.servlet.http.HttpServlet;
 7 import javax.servlet.http.HttpServletRequest;
 8 import javax.servlet.http.HttpServletResponse;
 9 
10 
11 public class ServletThreadDemo1 extends HttpServlet {
12 
13     int i=1;
14     public void doGet(HttpServletRequest request, HttpServletResponse response)
15             throws ServletException, IOException {
16         synchronized (ServletThreadDemo1.class) {//在java中,每个对象都有一把锁,这里的this指的就是Servlet对象
17             i++;
18             try {
19                 Thread.sleep(5000*2);
20             } catch (InterruptedException e) {
21                 e.printStackTrace();
22             }
23             response.getWriter().println(i+"");
24         }
25         
26     }
27 
28     public void doPost(HttpServletRequest request, HttpServletResponse response)
29             throws ServletException, IOException {
30         doGet(request, response);
31     }
32 }

 

2.sun公司给的解决方案是:若是某个Servlet实现了SingleThreadModel接口,那么Servlet引擎将以单线程模式来调用其service方法。 SingleThreadModel接口中没有定义任何方法,只要在Servlet类的定义中增长实现SingleThreadModel接口的声明便可。 对于实现了SingleThreadModel接口的Servlet,Servlet引擎仍然支持对该Servlet的多线程并发访问,其采用的方式是产生多个Servlet实例对象,并发的每一个线程分别调用一个独立的Servlet实例对象。 可是实现SingleThreadModel接口并不能真正解决Servlet的线程安全问题,由于Servlet引擎会建立多个Servlet实例对象,而真正意义上解决多线程安全问题是指一个Servlet实例对象被多个线程同时调用的问题。事实上,在Servlet API 2.4中,已经将SingleThreadModel标记为Deprecated(过期的)。线程

相关文章
相关标签/搜索