首页 > 其他分享 >Servlet的线程安全问题

Servlet的线程安全问题

时间:2022-10-27 13:33:41浏览次数:78  
标签:status Calculator cmd 安全 实例 线程 Servlet


文章目录

Servlet的线程安全问题

引入

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

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

Servlet的线程安全问题_安全

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)

Servlet的线程安全问题_线程安全_02

如何修复

1.实现 SingleThreadModel 接口

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

public class TestServlet extends HttpServlet implements SingleThreadModel

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

public static boolean status;

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

Servlet的线程安全问题_开发语言_03

还有一点很重要该接口在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://zhuanlan.zhihu.com/p/93708538​

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


标签:status,Calculator,cmd,安全,实例,线程,Servlet
From: https://blog.51cto.com/u_15847702/5800902

相关文章

  • Linux系统安全及应用
    Linux系统安全及应用......
  • C#在调用UI刷新时启用了不同的线程,导致数据异常的解决方案
    将原先的刷新函数封装如下原先的调用方式publicvoidRefreshGrid(){System.Diagnostics.Debug.WriteLine("CurrentThreadID:"+System.Threadi......
  • 安全周报2022-10-20
    PleaseSubscribeWechatOfficialAccount:信安科研人,获取更多的原创安全资讯每周新闻CISA通告ADVANTECH和日立工业电器的存在严重缺陷美国网络安全和基础设施安全局(CIS......
  • java多线程编程详细入门教程
    ##1、概念?线程是jvm调度的最小单元,也叫做轻量级进程,进程是由线程组成,线程拥有私有的程序技术器以及栈,并且能够访问堆中的共享资源。这里提出一个问题,为什么要用多......
  • 线程:生命周期
    线程生命周期我喜欢打比喻的方式,这样能记住每个周期的意思。如果你想去参加格斗比赛,报名了就是参数选手,此时你已是新建状态比赛那天,双方就位(还没开始打),互相握手阶......
  • 小程序图片安全检查
    借助临时CDN传递大数据到云函数实现图片安全检测最近在重构小程序恋爱小清单,在用云函数做图片的安全检测时报了一个错:cloud.callFunction:failError:dataexceedm......
  • 线程池实现服务隔离
    线程池实现服务隔离 问题分析#在微服务架构中,我们将业务拆分成一个个的服务,服务与服务之间可以相互调用,由于网络原因或者自身的原因,服务并不能保证服务的100%可用,如......
  • Java多线程(4):ThreadLocal
    您好,我是湘王,这是我的博客园,欢迎您来,欢迎您再来~ 为了提高CPU的利用率,工程师们创造了多线程。但是线程们说:要有光!(为了减少线程创建(T1启动)和销毁(T3切换)的时间),于是工程师们......
  • spdlog日志库源码:线程池thread_pool
    目录线程池thread_pool简介多生产者-多消费者阻塞队列模型阻塞与非阻塞方式插入数据取出数据overrun异常处理机制其他接口环形队列circular_qthreadpool模型threadpool实......
  • 速度快、时延低、更安全,华为云CDN助力企业创新发展!
    随着信息化时代的发展和互联网技术的进步,人们对网络连接质量的需求日益增加,因此需要更加强大的网络资源来实现信息传递、传输等功能。而传统的带宽资源无法满足这样一种要......