zoukankan      html  css  js  c++  java
  • 前几天,有人问"servlet是线程安全的吗?"

    前两天,有个人问我“servlet是线程安全的吗?“,我却很难给出一个很具体清晰的回答,今天重新整理一下思路,也复习一下那些被扔回给老师的理论。


    servlet是线程安全的吗?

    这个问题,在网上没有看到一个确切的答案,所以我们来分析一下:
    首先什么是线程安全?
    引用概念:如果你的代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码。如果每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的。

    那么我们都知道servlet是多线程的,同时一个servlet实现类只会有一个实例对象,也就是它是Singleton的,所以多个线程是可能会访问同一个servlet实例对象的。

    每个线程都会为数据实例对象开辟单独的引用,那么servlet会是线程安全的吗?

    要判断是否是线程安全,我们需要知道线程安全问题是由什么引起的。
    搜索得到答案:线程安全问题都是由全局变量及静态变量引起的。
    看到这个答案,突然想起很多年前调查过的一个bug, 那时我们系统中遗留的代码中写了很多全局变量,有一次发布后,客户反馈,当有多人同时进行某个操作时,我们的数据出了问题,那时我们调查后的结果就是:多人同步操作时,有些全局变量的值不对了,之后我们专门设一个人花了很多工夫来将所有全局变量都改成了局部变量了,并且项目要求以后不允许用全局变量。原来那时侯我就已经碰到过线程不安全的情况了啊,不过处理方式或者不用全局,或者加入同步,若加入同步同时也要考虑一下对程序效率会不会产生影响。

    由此可知,servlet是否线程安全是由它的实现来决定的,如果它内部的属性或方法会被多个线程改变,它就是线程不安全的,反之,就是线程安全的。

    在网上找到一个例子,如下:

    public class TestServlet extends HttpServlet {
         private int count = 0;  
          
         @Override
         protected void service(HttpServletRequest request, HttpServletResponse response)
                 throws ServletException, IOException {
             response.getWriter().println("<HTML><BODY>");
             response.getWriter().println(this + " ==> ");
             response.getWriter().println(Thread.currentThread() + ": <br>");
             for(int i=0;i<5;i++){
                 response.getWriter().println("count = " + count + "<BR>");
                 try {
                     Thread.sleep(1000);  
                     count++;  
                 } catch (Exception e) {
                     e.printStackTrace();
                 }
             }
             response.getWriter().println("</BODY></HTML>");
         }
     }


    当同时打开多个浏览器,输入http://localhost:8080/ServletTest/TestServlet时,他们显示的结果不同,这就说明了对于属性count来说,它是线程不安全的,
    为了解决这个问题,将代码重构,如下:

    public class TestServlet extends HttpServlet {
          private int count = 0;  
          private String synchronizeStr = "";
          @Override
         protected void service(HttpServletRequest request, HttpServletResponse response)
                 throws ServletException, IOException {
             response.getWriter().println("<HTML><BODY>");
             response.getWriter().println(this + " ==> ");
             response.getWriter().println(Thread.currentThread() + ": <br>");
             synchronized (synchronizeStr){
                 for(int i=0;i<5;i++){
                     response.getWriter().println("count = " + count + "<BR>");
                     try {
                         Thread.sleep(1000);  
                         count++;  
                     } catch (Exception e) {
                         e.printStackTrace();
                     }
                 }
             }
             response.getWriter().println("</BODY></HTML>");
         }
     }


  • 相关阅读:
    使企点QQ来消息时不自动弹出窗口(以避免错过旧的消息和避免正在回复A时自动定位到B从而影响客服效率)
    8款开源聊天软件
    博客园设置皮肤(宽屏等)及选择文本编辑器
    Windows Server 2019 设置使用照片查看器查看图片
    使windows10重启后打开上次的文件夹和程序
    TinyMCE 5 富文本编辑器好
    wordpress 安装 Elementor PRO 插件(破解版)
    无法打印,提示“windows 打印后台处理程序 没有运行”的解决方案
    第一次将代码提交至git error: failed to push some refs to 'https://gitee.com/xxx/test.git'
    git本地和远程的关联问题
  • 原文地址:https://www.cnblogs.com/itTeacher/p/2769822.html
Copyright © 2011-2022 走看看