0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

Controller并发安全的解决办法

Android编程精选 来源:今日头条 作者:微说互联网 2022-06-15 17:10 次阅读
单例模式(Singleton)是程序设计中一种非常重要的设计模式,设计模式也是Java面试重点考察的一个方面。面试经常会问到的一个问题是:SpringMVC中的Controller是单例还是多例,很多同学可能会想当然认为Controller是多例,其实不然。

根据Tomcat官网中的介绍,对于一个浏览器请求,tomcat会指定一个处理线程,或是在线程池中选取空闲的,或者新建一个线程。

Each incoming request requires a thread for the duration of that request. If more simultaneous requests are received than can be handled by the currently available request processing threads, additional threads will be created up to the configured maximum (the value of the maxThreads attribute). If still more simultaneous requests are received, they are stacked up inside the server socket created by the Connector, up to the configured maximum (the value of the acceptCountattribute). Any further simultaneous requests will receive "connection refused" errors, until resources are available to process them.

—— https://tomcat.apache.org/tomcat-7.0-doc/config/http.html

在Tomcat容器中,每个servlet是单例的。在SpringMVC中,Controller 默认也是单例。 采用单例模式的最大好处,就是可以在高并发场景下极大地节省内存资源,提高服务抗压能力。

单例模式容易出现的问题是:在Controller中定义的实例变量,在多个请求并发时会出现竞争访问,Controller中的实例变量不是线程安全的。

Controller不是线程安全的

正因为Controller默认是单例,所以不是线程安全的。如果用SpringMVC 的 Controller时,尽量不在 Controller中使用实例变量,否则会出现线程不安全性的情况,导致数据逻辑混乱。

举一个简单的例子,在一个Controller中定义一个非静态成员变量 num 。通过Controller成员方法来对 num 增加。

@Controller
publicclassTestController{
privateintnum=0;

@RequestMapping("/addNum")
publicvoidaddNum(){
System.out.println(++num);
}
}

在本地运行后:

  • 首先访问 http:// localhost:8080 / addNum,得到的答案是1;
  • 再次访问 http:// localhost:8080 / addNum,得到的答案是 2。

两次访问得到的结果不同,num已经被修改,并不是我们希望的结果,接口的幂等性被破坏。

从这个例子可以看出,所有的请求访问同一个Controller实例,Controller的私有成员变量就是线程共用的。某个请求对应的线程如果修改了这个变量,那么在别的请求中也可以读到这个变量修改后的的值

Controller并发安全的解决办法

如果要保证Controller的线程安全,有以下解决办法:

  • 尽量不要在 Controller 中定义成员变量 ;

如果必须要定义一个非静态成员变量,那么可以通过注解 @Scope(“prototype”) ,将Controller设置为多例模式。

@Controller
@Scope(value="prototype")
publicclassTestController{
privateintnum=0;

@RequestMapping("/addNum")
publicvoidaddNum(){
System.out.println(++num);
}
}

Scope属性是用来声明IOC容器中的对象(Bean )允许存在的限定场景,或者说是对象的存活空间。在对象进入相应的使用场景之前,IOC容器会生成并装配这些对象;当该对象不再处于这些使用场景的限定时,容器通常会销毁这些对象。

Controller也是一个Bean,默认的 Scope 属性为Singleton ,也就是单例模式。如果Bean的 Scope 属性设置为 prototype 的话,容器在接受到该类型对象的请求时,每次都会重新生成一个新的对象给请求方。

  • Controller 中使用 ThreadLocal 变量。每一个线程都有一个变量的副本。
publicclassTestController{
privateintnum=0;
privatefinalThreadLocaluniqueNum=
newThreadLocal(){
@OverrideprotectedIntegerinitialValue(){
returnnum;
}
};

@RequestMapping("/addNum")
publicvoidaddNum(){
intunum=uniqueNum.get();
uniqueNum.set(++unum);
System.out.println(uniqueNum.get());
}
}

以上代码运行以后,每次请求 http:// localhost:8080 / addNum , 得到的结果都是1。

更严格的做法是用AtomicInteger类型定义成员变量,对于成员变量的操作使用AtomicInteger的自增方法完成。

总的来说,还是尽量不要在 Controller 中定义成员变量为好。

原文标题:如何保证 Controller 的并发安全

文章出处:【微信公众号:Android编程精选】欢迎添加关注!文章转载请注明出处。

审核编辑:汤梓红
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • Controller
    +关注

    关注

    0

    文章

    397

    浏览量

    57074
  • singleton
    +关注

    关注

    0

    文章

    3

    浏览量

    5264
  • 线程安全
    +关注

    关注

    0

    文章

    13

    浏览量

    2456
  • SpringMVC
    +关注

    关注

    0

    文章

    18

    浏览量

    5753

原文标题:如何保证 Controller 的并发安全

文章出处:【微信号:AndroidPush,微信公众号:Android编程精选】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    关于TCP/IP门禁系统有哪些安全问题?有什么解决办法

    关于TCP/IP门禁系统有哪些安全问题?有什么解决办法
    发表于 05-31 06:04

    华硕笔记本声卡驱动无法安装的解决办法

    华硕笔记本声卡驱动无法安装的解决办法
    发表于 01-18 10:10 3536次阅读

    声卡硬件维修的常见问题及解决办法

    声卡硬件维修的常见问题及解决办法 常见故障一:声卡无声   出现这种故障常见的原因有:
    发表于 02-23 14:25 2521次阅读

    误码特性,误码产生的机理及解决办法

    误码特性,误码产生的机理及解决办法
    发表于 03-19 17:10 2246次阅读

    UPS电源输入跳闸浅析及解决办法

    UPS电源输入跳闸浅析及解决办法解析
    发表于 11-10 16:42 89次下载
    UPS电源输入跳闸浅析及<b class='flag-5'>解决办法</b>

    Matlab编程常见错误与解决办法

    Matlab编程常见错误与解决办法求人不如求己
    发表于 03-16 15:58 0次下载

    压榨辊轴承位磨损有哪些解决办法

    压榨辊轴承位磨损有哪些解决办法
    发表于 01-19 09:45 4次下载

    ESP32勘误表及解决办法

    电子发烧友网站提供《ESP32勘误表及解决办法.pdf》资料免费下载
    发表于 09-23 11:51 0次下载
    ESP32勘误表及<b class='flag-5'>解决办法</b>

    电脑右键管理打开失败的解决办法

    此电脑右键管理打不开怎么办 电脑右键管理打开失败的解决办法
    发表于 09-28 09:56 0次下载

    J-Link连接MCU失败解决办法

    J-Link连接MCU失败解决办法
    的头像 发表于 10-18 17:43 1058次阅读
    J-Link连接MCU失败<b class='flag-5'>解决办法</b>

    硬盘故障的3个终极解决办法

    电子发烧友网站提供《硬盘故障的3个终极解决办法.pdf》资料免费下载
    发表于 10-20 10:46 0次下载
    硬盘故障的3个终极<b class='flag-5'>解决办法</b>

    细碎机轴承位磨损问题的解决办法

    【设备故障】细碎机轴承位磨损问题的解决办法
    发表于 10-27 16:36 0次下载

    Protel99 与WIN10系统冲突解决办法

    PROTEL99 与WIN10系统冲突解决办法
    的头像 发表于 11-20 09:30 3894次阅读
    Protel99 与WIN10系统冲突<b class='flag-5'>解决办法</b>

    Profinet IO通信故障的解决办法

    Profinet IO通信故障可能由多种原因引起,以下是一些常见的通信故障及其解决办法
    的头像 发表于 03-08 11:27 1067次阅读

    常见MCU故障及解决办法

    微控制器单元(MCU)是现代电子设备中的核心组件,负责处理和控制各种功能。然而,由于各种原因,MCU可能会出现故障。以下是一些常见的MCU故障及其解决办法: 1. 电源问题 故障现象: MCU无法
    的头像 发表于 11-01 13:41 530次阅读