Spring Controller中全局变量引起的线程安全问题

spring+tomcat 用户每次发请求,tomcat 站在线程的角度是如何处理用户请求的,spinrg的bean 是共享的吗 对于 spring+tomcat 用户每次发请求,tomcat 站在线程的角度是如何处理的 比如 bio nio apr 等情况 tomcat 配置文件中 maxThreads 的数量是相对于谁来说的? 以及 spring Controller 中的全局变量:各种bean 对于线程来说是共享的吗? 阅读详情

在Spring中,注解@Controller去修饰一个类时,默认这个类是单例。但是WEB容器为了性能,必然是多线程的去处理HTTP请求,多线程的HTTP请求经过WEB容器转化为servlet请求,接着由Spring的DispatcherServlet分发到对应的Controller处理类。所以在单例的Controller类中,如果存在全局变量,必然会存在线程安全问题。

下面将示范多种常用写法,有些不会引起线程安全,有些会引起线程安全。

示例1:

这种写法不会引起线程安全,因为 HttpServletRequest 与 HttpServletResponse 申明为形参,形参是局部变量,而局部变量存储在栈中,每个线程又有独立的栈空间,故不会引起线程安全问题。

 

@Controller
public class TestController {
    
    @RequestMapping(value = "/test1")
    public void thread1(HttpServletRequest request, HttpServletResponse response) throws Exception{
        
        System.out.println("客户端:" + request.getHeader("Thread"));
    }
}

接下来启动10个线程去访问这个接口,在http请求的头部设置线程的名字,模拟10个不同http客户端请求。

public class HttpThread {
    
    public static void main(String[] args) {
        
        for (int i = 0; i < 10; i++) {
            new Thread(new Runnable(){
                public void run(){
                    CloseableHttpClient httpclient = HttpClients.createDefault();
                    HttpGet httpGet = new HttpGet("http://localhost:8080/test1");
                    System.out.println(Thread.currentThread().getName());
                    httpGet.setHeader("Thread", Thread.currentThread().getName());
                    try {
                        httpclient.execute(httpGet);
                    } catch (ClientProtocolException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    } catch (IOException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
            }).start();
        }
    }
}

输出如下:
可以看到10个客户端都已经正常访问,没有线程安全问题。


 

示例2:
        下面这种写法会引起线程安全问题。有时候一个Controller类中会有多个方法,为了代码的简洁,不想在多个方法中都要写HttpServletRequest request, HttpServletResponse response。把HttpServletRequest,HttpServletResponse 申明为全局变量 ,用@ModelAttribute注解修饰一个方法,并在这个方法中初始化request和response。就可在多处引用。但是这种写法会引起线程安全问题。

@Controller
public class TestController {
    
    public HttpServletRequest request;
    
    public HttpServletResponse response;
    
    /**
     * ModelAttribute 注解代表只要调用TestController类的方法,就一定会先执行该方法,
     * 此处在方法内初始化了Servlet对象。
     * @param request
     * @param response
     */
    @ModelAttribute  
    public void setReqAndRes(HttpServletRequest request, HttpServletResponse response){  
        this.request = request;  
        this.response = response;  
    } 
    
    @RequestMapping(value = "/test1")
     public void thread1() throws Exception{
        
     System.out.println("客户端:" + request.getHeader("Thread"));
     }
}

起30个线程去访问接口:

public class HttpThread {
    
    public static void main(String[] args) {
        
        for (int i = 0; i < 30; i++) {
            new Thread(new Runnable(){
                public void run(){
                    CloseableHttpClient httpclient = HttpClients.createDefault();
                    HttpGet httpGet = new HttpGet("http://localhost:8080/test1");
                    System.out.println(Thread.currentThread().getName());
                    httpGet.setHeader("Thread", Thread.currentThread().getName());
                    try {
                        httpclient.execute(httpGet);
                    } catch (ClientProtocolException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    } catch (IOException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    }
                }
            }).start();
        }
    }
}

结果如下:
可以看到客户端13出现了多次,而客户端4没有出现。此时如果这个接口里面有response。

response.getWriter().write(str);

那么,客户端4将接受不到返回,并且客户端13接收到的结果也有可能是错误的。

解释一下为什么会出现线程不安全的问题:

示例3:
使用@Autowired注解可以解决示例2的问题。代码如下:

@Controller
public class TestController {
    
    @Autowired
    public HttpServletRequest request;
    
    @Autowired
    public HttpServletResponse response;
    
    @RequestMapping(value = "/test1")
    public void thread1() throws Exception{
        
        System.out.println("客户端:" + request.getHeader("Thread"));
    }
}

经过多次实验,示例3的写法不会产生Servlet线程安全问题。大家也可以试一试。

后记:
具体@Autowired注入为什么可以解决线程安全问题,这个估计要看源码才能知道。如果有高人知晓,请多多指教。

 


作者:linjiajiam
链接:https://www.jianshu.com/p/413a13b3c9cd
来源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

10、网络安全工具:Bettercap 与 Web 应用测试工具全解析 本文详细解析了网络安全工具Bettercap及其在中间人攻击和无线攻击中的应用,同时介绍了多种Web应用测试工具,如Amass、Cadaver、Dirb等,并探讨了工具的使用场景、流程、注意事项以及未来发展趋势,为网络安全测试提供了全面的指导。 阅读详情

相关推荐

【Zemax光学设计实训一】---单透镜光学设计

建立一个焦距为100mm、入瞳直径为25mm的单透镜系统,该透镜中心厚度为4mm,其两个面的曲率半径分别为100mm、-100mm,全视场2w=10°。该系统在可见光下工作,采用BK7玻璃,光阑设置在人射光线遇到的透镜的第一个光学表面;并对其展开优化。

yh的博客 3620

Java中的多线程安全问题及解决方法

线程安全 如果有多个线程在同时运行,而这些线程可能会同时运行这段代码。程序每次运行结果和单线程运行的结果是一样 的,而且其他的变量的值也和预期的是一样的,就是线程安全的。 我们通过一个案例,演示线程的安全问题: 电影院要卖票,我们模拟电影院的卖票过程。假设要播放的电影是 “葫芦娃大战奥特曼”,本次电影的座位共100个 (本场电影只能卖100张票)。 我们来模拟电影院的售票窗口,实现多个窗口同时卖 “葫芦娃大战奥特曼”这场电影票(多个窗口一起卖这100张票) 需要窗口,采用线程对象来模拟;需要票,Runnab

Rocky balboa 2636

MATLAB实战:用ARMAX模型搞定电力系统惯量评估(附完整代码)

本文详细介绍了如何利用MATLAB中的ARMAX模型进行电力系统惯量评估,解决新能源占比提高带来的系统惯量下降问题。通过系统辨识技术,从电网运行数据中准确提取惯量参数,并提供完整的代码实现,帮助工程师快速应用于实际工程。

peach的博客 638

JDK1.9-线程安全

2.1 线程安全 如果有多个线程在同时运行,而这些线程可能会同时运行这段代码。程序每次运行结果和单线程运行的结果是一样 的,而且其他的变量的值也和预期的是一样的,就是线程安全的。 我们通过一个案例,演示线程的安全问题: 电影院要卖票,我们模拟电影院的卖票过程。假设要播放的电影是 “葫芦娃大战奥特曼”,本次电影的座位共100个 (本场电影只能卖100张票)。 我们来模拟电影院的售票窗口,实现多个窗口...

逍遥云恋 699

电源完整性之Cadence Sigrity Power DC_电热协同仿真

之前和大家分享过电源完整性之仿真设计原理链接: link.今天接着上一篇文章总结一下电源直流压降的的仿真操作流程及一些simulation中的设置参数,用到的是Cadence Sigrity 中的Power DC组件,来操作一下电热协同仿真,下面开始享受仿真的快乐吧: 第0步:仿真简介 电热协同仿真把电和热相互的影响考虑到了一起。因为电导率并不是固定不变的,而是和温度有关,随着温度的升高导电率会下降。同样电流流径电阻的时候会产生热量,此热量为焦耳热。因此为了获得准确的仿真信息,应考虑电与热的互相影响,进行电

刘小同学的博客 1万+

win11系统ping另一台电脑上VMware虚拟机的IP

我是用了两台电脑,所以刚才遇到一个问题就是两台电脑的IP 在同一局域网内ping不通。于是就找了很多资料,经过坚强的绝望后终于解决了。 下开始解决问题: VMWare提供了三种工作模式:bridged(桥接模式)、NAT(网络地址转换模式)和host-only(主机模式)。 1. bridged(桥接模式)   在这种模式下,VMWare虚拟出来的操作系统就像是局域网中的一台独立主机,它可以访问网内任何一台机器。在桥接模式下,你需要手工为虚拟系统配置IP地址、子网掩码,而且还要和宿主机器处于同一网段,这样虚

qq_42817360的博客 3239

线程安全和线程安全的解决方案

如果多个线程同时运行,而这些线程同时具有修改某段代码的能力。程序不管是单线程执行还是多线程执行,结果都一样,并且变量与预期一样,就是线程安全。线程安全问题都是全局变量或者静态变量导致的,如果每个线程中对全局变量、静态变量只有读操作,而没有写操作,通常这个全局变量是线程安全的;如果多个线程同时执行写操作,就需要考虑到线程同步问题,否则就是出现线程安全问题。

不积跬步,无以至千里 696

详解Σ-Δ型ADC拓扑结构的基本原理

现在,总环路滤波器的H(f)具有更大的滚降,Mod 2型的噪声传递函数具有40 dB/十倍频程的上升速率。同样,当正弦波输入为负满量程时,+1和–1之间的转换会减少,输出以–1为主。噪声传递函数是一个高通滤波器函数,提供噪声整形,在DC附近的较低频率,对量化噪声有很强的抑制。H(f)是环路滤波器的函数,定义噪声和信号的传递函数。Σ-Δ型ADC的噪底由热噪声决定,而不受量化噪声的限制。量化噪声为量化器的输入与输出之差。图5. Mod 1 Σ-Δ环路的线性模型(b),包括方程、滤波器、信号和噪声传递函数图。

qq_43416206的博客 1810

Spring Controller中全局变量引发的线程安全问题

引自:Spring Controller中全局变量引发的线程安全问题 - JavaShuo 在Spring中,注解@Controller去修饰一个类时,默认这个类是单例。可是WEB容器为了性能,必然是多线程的去处理HTTP请求,多线程的HTTP请求通过WEB容器转化为servlet请求,接着由Spring的DispatcherServlet分发到对应的Controller处理类。因此在单例的Controller类中,若是存在全局变量,必然会存在线程安全问题。安全 下面将示范多种经常使用写法,有些不会引发

qq_35648576的博客 2734

组态王通过以太网与西门子S7-200 SMART PLC通讯案例详解

通过以上步骤,我们成功实现了组态王与西门子S7-200 SMART PLC的以太网通讯。这一技术不仅提高了工业自动化系统的灵活性和可靠性,还为初学者提供了一个实用的学习案例。希望本文能帮助您快速掌握组态王与西门子S7-200 SMART PLC的通讯技术。如有任何疑问,欢迎留言讨论!

2401_88785500的博客 2006

Android 13.0 双屏时触摸失效问题排查与修复

摘要:本文记录了RK3588 Android12开发板上主屏触摸失效问题的排查与解决过程。通过分析发现,USB触摸设备被错误关联到辅屏(displayId=3)而非主屏(displayId=0)。解决方案是修改TouchInputMapper.cpp,强制触摸设备使用INTERNAL viewport(主屏),并保持设备在viewport不活跃时仍启用。该修改涉及约40行代码,有效解决了多显示器环境下触摸设备错误映射的问题,同时提供了详细的调试方法和注意事项。

ip0417的博客 354

Spring的线程安全

参考: http://www.importnew.com/27440.html https://www.cnblogs.com/wxd0108/p/5524756.html https://blog.youkuaiyun.com/cws1214/article/details/51901108 Spring作为一个IOC/DI容器,帮助我们管理了许许多多的“bean”。但其实,Spring并没有保证这些对象的...

try to do 2220

C#实现OPC客户端与S7-1200 PLC通信:工控场景稳定通信的实战指南(附完整代码)

标准化优先:OPC UA是工业通信的标准,相比直接通信,更适合多设备集成的工控场景;稳定性第一:必须封装断线重连、异常处理、资源释放逻辑,满足7×24小时运行需求;效率优化:高频采集场景优先用批量读写,避免单个变量频繁请求;细节把控:节点ID、变量类型、端口配置等细节是新手最容易踩坑的地方,建议先用UA Expert验证。这套代码和方案已在多个工业项目中落地,从单台S7-1200到多台S7-1200/1500集群,都能稳定运行。

这里只有干货:从 Modbus 通信到 MES 对接,从 YOLO 训练到工控机部署,带你搞定工业软件开发全流程。 1041

1.为什么全局变量不是线程安全的?

问题:经常有人告诉我们不要在controller或者service中使用全局属性和变量,说这样会导致线程安全问题,那线程安全问题是怎么引起的呢?本人在初学线程的时候,就曾纠结过这个问题很久!下面通过一个实例演示下并发导致的线程安全问题。 @RestController @RequestMapping("/thread") public class ThreadController { @Autowired private ThreadService threadService;

永不妥协的专栏 709

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

ET2012新版免狗免安装绿色软件

ET2012新版免狗免安祖昂绿色软件。,新界面,新视觉,

SpringMVC Controller是单例还是多例?线程安全吗?如何解决呢?

文章目录示例结论验证 Controller是单例还是多例?线程安全吗?如何解决呢? 示例 @RestController @RequestMapping("/laker") public class HelloWordController { private int num = 1; @GetMapping @ApiOperation(value = "根据id查询") public int get() { int i = num++; Sys

laker的博客 809

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

Spring MVC Controller线程安全问题

spring生成对象默认是Singleton(单例)的,这样可以避免每次创建新的对象,减少垃圾对象。当request过来,不用每次创建Controller,会用原来的instance去处理。此时会存在一个问题,这个controllerl内部声明了实例变量,当多个线程调用它的时候,多个线程访问的是同一个对象变量,就会产生线程安全问题。 解决在controller内部声明全局变量的方法: 1.成员变量定义在方法中(推荐), 2.在Controller中使用ThreadLocal来做数据隔离, 3.在

weixin_46217160的博客 918

Springmvc controller 是单例的线程不安全的

Springmvc controller 是单例的线程不安全的 当时有这么一个面试题 随手记录一下了; spring的controller默认是单例的。 spring的bean作用域有5个,如下: singleton:单例模式,当spring创建applicationContext容器的时候,spring会初始化所有的该作用域实例,加上lazy-init就可以避免预处理。 prototype:原型模式,每次通过getBean获取该bean就会产生一个新的实例,创建后spring将不再对齐进行管理。 requ

973

SpringMvc线程安全问题(个人感悟)

由于springmvc是singleton单实例多线程(并发能力好)的,所以假如存在全局变量时就容易导致线程安全问题, (局部变量是线程安全的,为什么? 参考 https://blog.youkuaiyun.com/keocce/article/details/105860971?utm_medium=distribute.pc_relevant.none-task-blog-baidujs_baidulandingword-1&spm=1001.2101.3001.4242 )线程安全问题其实归根结底就是

zsw5462321945的博客 747

springmvc中controller不要定义全局变量

因为controller是默认单例模式,高并发下全局变量会出现线程安全问题 现这种问题如何解决呢? 第一种方式: 既然是全局变量惹的祸,那就将全局变量都编程局部变量,通过方法参数来传递。 第二种方式: jdk提供了java.lang.ThreadLocal,它为多线程并发提供了新思路。 第三种:使用@Scope("session"),会话级别 @Controller ...

weixin_33387378的博客 5250

Spring Controller全局变量引起的问题

一直以来都是方法之间进行参数的传递,对参数进行各种修改然后返回这样没有任何的问题,直到昨天遇到了我的同事写的代码,项目使用的是springcloud全家桶,他在代码中编写如下; 接口看起来没什么问题,入参正常,返回一个集合,声明了一个全局变量List集合matchInvoiceList用来进行接收某些方法之间的数据,并且进行对数据的操作,但是这样有两个非常要命的问题; 问题: 1.spring是单例模式,并发的场景下,全局变量会有线程安全的问题; 2.会出现第二次访问这个接口的时候,集合并没有重新实例化,

weixin_44887276的博客 2203

在SpringMVC中的Controller里面定义全局变量

使用SpringMVC的时候,如果想要在Controller中定义一个全局变量,并且实现在不同用户访问程序的时候,所得到的全局变量不一样的(线程安全的),这个时候就可以用Spring的注解@Scope来实现: @Controller //把这个bean 的范围设置成session,表示这bean是会话级别的, @Scope("session") public class XxxContr...

Notebookdong的专栏 2760

在Spring MVC Controller中注入HttpServletRequest对象会不会造成线程安全的问题

做法: 1、比如我们在Controller的方法中,通常是直接将HttpServletRequest做为参数,而为了方便节省代码,通常会定义为全局变量,然后使用@Autowire注入。 说明: 1、观察了网上的说法,好像没有统一的解释,有些说会线程安全,有些则说不会。 2、如果按照一些方法进行测试,好像也会出现,而换另一种方法测试,好像也不会出现。 3、可能和Spring的版本...

angou6476的博客 265

springMVC的Controller使用全局变量

使用SpringMVC的时候,如果想要在Controller中定义一个全局变量

情人节也放假 8252

SpringMVC的Controller单例线程安全问题

这个文章验证了单例http://blog.youkuaiyun.com/darkdragonking/article/details/52367186 每个请求都会分配一个线程处理请求http://www.cnblogs.com/doit8791/p/4093808.html Java内存区的分配http://blog.youkuaiyun.com/maoyeqiu/article/details/50564075 总的来讲就是controller可以自定义为单例的,当请求发送请求时,每个请求会有一个线程处理,全局变量会被共享,每

方方园园的博客 1170

关于springmvc中的controller有无并发阻塞问题

这里写自定义目录标题欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题,有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个自定义列表如何创建一个注脚注释也是必不可少的KaTeX数学公式新的甘特图功能,丰富你的文章UML 图表FLowchart流程图导出与导入导出导入 欢迎使用Ma...

qq_23134039的博客 4759

SSM中@Controller线程安全问题

SSM中:Spring容器线程安全问题 问题来源:在一次学完SSM之后的一次尝试用SSM完成老师的Web实验发现了一个线程安全问题: 环境:Spring+Spring MVC +Mybatis web容器:tomcat 问题是:在Controller层中,多个用户请求这个@RequestMapping("/register")资源后,对象user被所有请求的用户共同使用,数据也是共享,可以相互篡改,无法获得正确的数据 @Controller @RequestMapping("/account") publi

码码哈哈的博客 931
上一篇: Visual Studio Code 终端无法使用问题-已解决
下一篇: Lvs+keepalived+Nginx双机热备实现Nginx高可用
AndyChen9988
博客等级 码龄11年 276粉丝 89原创
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值