• Servlet的线程安全


    Servlet的线程安全

    一、什么是Servlet的线程安全

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

    所谓线程安全就是一个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)

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

     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(过时的)。

    天行健,君子以自强不息
  • 相关阅读:
    17.1.1.2 Setting the Replication Slave Configuration
    17.1.1 How to Set Up Replication
    ffmpeg结构体以及函数介绍(二) 分类: ffmpeg-SDL-VLC-Live555 2013-08-22 18:03 451人阅读 评论(0) 收藏
    ffmpeg结构体以及函数介绍(一) 分类: ffmpeg-SDL-VLC-Live555 2013-08-22 18:01 543人阅读 评论(0) 收藏
    ffmpeg入门之 Tutorial01 分类: ffmpeg-SDL-VLC-Live555 2013-08-22 17:54 495人阅读 评论(0) 收藏
    uclibc和glibc的差别 分类: arm-linux-Ubuntu 2013-08-21 17:42 499人阅读 评论(0) 收藏
    Cramfs、JFFS2、YAFFS2全面对比 分类: arm-linux-Ubuntu 2013-08-21 10:42 904人阅读 评论(0) 收藏
    Hi3531 SDK v2.0.8.0 安装 分类: HI3531 2013-08-21 10:25 2748人阅读 评论(1) 收藏
    arm-linux-gcc: Command not found 问题解析 . 分类: arm-linux-Ubuntu 2013-08-21 08:43 855人阅读 评论(0) 收藏
    Hi3531 SDK 安装以及升级使用说明 分类: HI3531 2013-08-20 17:26 2657人阅读 评论(0) 收藏
  • 原文地址:https://www.cnblogs.com/god-y-l/p/6847077.html
Copyright © 2020-2023  润新知