Servlet的线程安全问题

 更新时间:2022年02月15日 15:51:17   作者:Y4tacker  
本文主要介绍了Servlet的线程安全问题,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

引入

首先看看这样的代码,有什么问题

这里既要求cmd不能包含Calculator又必须要包含Calculator,能做到吗,当然是可以的

在这里插入图片描述

Servlet的多线程机制

Servlet实际上是一个单件,当我们第一次请求某个Servlet时,Servlet容器将会根据web.xml配置文件或者是注解实例化这个Servlet类,之后如果又有新的客户端请求该Servlet时,则一般不会再实例化该Servlet类,这说明了什么呢?简单来说,当多个用户一起访问时,得到的其实是同一个Servlet实例,这样的话,他们对实例的成员变量的修改其实会影响到别人,所以在开发的时候如果没有注意这个问题往往会有一些额安全问题,而往往Servlet的线程安全问题主要是由于实例变量使用不当而引起

因此我们再看上面的代码,很明显我们看到了这个status状态变量是实例变量,当然这里为了突出并发的效果,这里加了一个延时,这里简简单单用python实现竞争,也不必上多线程了简单点

url = "http://127.0.0.1:8080/?cmd=open -na Calculator"

while 1:
    r = requests.get(url)
    if "Cal" in r.text:
        print(r.text)
url = "http://127.0.0.1:8080/?cmd=ls"

while 1:
    r = requests.get(url)

如何修复

1.实现 SingleThreadModel 接口

该接口指定了系统如何处理对同一个Servlet的调用。如果一个Servlet被这个接口指定,那么在这个Servlet中的service方法将不会有两个线程被同时执行,当然也就不存在线程安全的问题。这种方法只要继承这个接口就行了,因此将我们上面的代码改为

public class TestServlet extends HttpServlet implements SingleThreadModel 

这样你觉得就完全安全了吗??答案也不是,如果我们将上面的对状态的定义加上static呢

public static boolean status;

lol,还是可以成功,原因是SingleThreadModel不会解决所有的线程安全隐患。会话属性和静态变量仍然可以被多线程的多请求同时访问

在这里插入图片描述

还有一点很重要该接口在Servlet API 2.4中将不推荐使用。

2.避免使用成员变量

既然问题出自成员变量,那么我们就尽量避免去使用它

将上面的代码改为

public class TestServlet extends HttpServlet{

//    public  boolean status;
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        boolean status = true;
        String cmd = req.getParameter("cmd");
        if (cmd.contains("Calculator")) {
            status = false;
            try {
                Thread.sleep(1000);
            }catch (Exception e){

            }
        }

        if (!status) {
            return;
        }
        if (cmd.contains("Calculator")){
            resp.getWriter().write(cmd);
        }
    }
}

3.同步对共享数据的操作

使用synchronized 关键字能保证一次只有一个线程可以访问被保护的区段,因此可以将代码写为

public class TestServlet extends HttpServlet{

    public  boolean status;
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        String cmd = req.getParameter("cmd");
        boolean status;
        synchronized(this) {
            status = true;

            if (cmd.contains("Calculator")) {
                status = false;
                try {
                    Thread.sleep(5000);
                } catch (Exception e) {

                }
            }
        }

        if (!status) {
            return;
        }
        if (cmd.contains("Calculator")){
            resp.getWriter().write(cmd);
        }
    }
}

思考与小结

但是如果利用上面三种方式去修复,这样就完全没问题了吗?并不是

比如实现SingleThreadModel以及在程序中使用同步来保护要使用的共享的数据,在实际业务当中这也会使得我们系统的性能大大下降,这也是我们不太希望看到的,前者为每个新的请求创建一个单独的Servlet实例,这将引起大量的系统开销,而后者被同步的代码块在同一时刻也只能有一个线程执行它,这也会导致在高并发的情况下,同时处理请求的吞吐量显著的降低

因此,在Serlet中避免使用实例变量或许是更好的选择,但如果无法避免,但如果无法避免,也应该尽量做到去同步可用性最小的代码路径

参考文章

https://www.cnblogs.com/chanshuyi/p/5052426.html

https://zhuanlan.zhihu.com/p/93708538

https://www.jianshu.com/p/06260e0667a9

到此这篇关于Servlet的线程安全问题 的文章就介绍到这了,更多相关Servlet 线程安全 内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Spring Security OAuth2 实现登录互踢的示例代码

    Spring Security OAuth2 实现登录互踢的示例代码

    这篇文章主要介绍了Spring Security OAuth2实现登录互踢的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-04-04
  • idea配置tomcat,idea配置web下lib的包详解

    idea配置tomcat,idea配置web下lib的包详解

    这篇文章主要介绍了idea配置tomcat,idea配置web下lib的包,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-05-05
  • java:程序包javafx.geometry不存在问题及解决

    java:程序包javafx.geometry不存在问题及解决

    这篇文章主要介绍了java:程序包javafx.geometry不存在问题及解决,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-08-08
  • 基于Java的正则表达式

    基于Java的正则表达式

    正则表达式,又称正规表示法、常规表示法(英语:Regular Expression,在代码中常简写为regex、regexp或RE),计算机科学的一个概念
    2017-05-05
  • Java 中的抽象介绍

    Java 中的抽象介绍

    这篇文章主要介绍了Java 中的抽象,数据抽象是一种仅向用户显示基本细节的属性。不向用户显示琐碎或非必需的单元,下面文章Java抽象详细内容,需要的朋友可以参考一下
    2021-12-12
  • Java双重校验锁单例原理

    Java双重校验锁单例原理

    大家好,本篇文章主要讲的是Java双重校验锁单例原理,感兴趣的同学赶快来看一看吧,对你有帮助的话记得收藏一下
    2022-01-01
  • 详解如何在Java中使用阿里云对象存储OSS

    详解如何在Java中使用阿里云对象存储OSS

    Java是世界上最流行的编程语言之一,拥有着广泛的应用场景和强大的生态系统,阿里云对象存储 OSS 是一种企业级的云存储服务,本文将介绍如何在 Java 中使用阿里云对象存储 OSS,并写一点相应的代码示例供大家参考
    2023-06-06
  • 学习Java多线程之同步

    学习Java多线程之同步

    这篇文章主要为大家详细介绍了Java多线程之同步,感兴趣的小伙伴们可以参考一下
    2016-02-02
  • 简单了解Spring Boot及idea整合jsp过程解析

    简单了解Spring Boot及idea整合jsp过程解析

    这篇文章主要介绍了简单了解Spring Boot及idea整合jsp过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-11-11
  • MyEclipse打开文件跳转到notepad打开问题及解决方案

    MyEclipse打开文件跳转到notepad打开问题及解决方案

    windows系统打开README.md文件,每次都需要右键选择notepad打开,感觉很麻烦,然后就把README.md文件打开方式默认选择了notepad,这样每次双击就能打开,感觉很方便,这篇文章主要介绍了MyEclipse打开文件跳转到notepad打开问题,需要的朋友可以参考下
    2024-03-03

最新评论