论坛
潜水/灌水快乐,沉淀知识,认识更多同行。
ToB圈子
加入IT圈,遇到更多同好之人。
朋友圈
看朋友圈动态,了解ToB世界。
ToB门户
了解全球最新的ToB事件
博客
Blog
排行榜
Ranklist
文库
业界最专业的IT文库,上传资料也可以赚钱
下载
分享
Share
导读
Guide
相册
Album
记录
Doing
应用中心
搜索
本版
文章
帖子
ToB圈子
用户
免费入驻
产品入驻
解决方案入驻
公司入驻
案例入驻
登录
·
注册
账号登录
立即注册
找回密码
用户名
Email
自动登录
找回密码
密码
登录
立即注册
首页
找靠谱产品
找解决方案
找靠谱公司
找案例
找对的人
专家智库
悬赏任务
圈子
SAAS
IT评测·应用市场-qidao123.com技术社区
»
论坛
›
安全
›
终端安全
›
Spring MVC 中是怎样保证Controller的并发安全? ...
Spring MVC 中是怎样保证Controller的并发安全?
半亩花草
论坛元老
|
2024-12-30 13:27:55
|
显示全部楼层
|
阅读模式
楼主
主题
1779
|
帖子
1779
|
积分
5337
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要
登录
才可以下载或查看,没有账号?
立即注册
x
在 Spring MVC 中,默认情况下,@Controller 是单例的,这意味着所有请求共享一个 Controller 实例。在并发请求的情况下,多个线程会同时访问这个控制器实例。为确保并发安全,Spring 并不会自动对 Controller 举行线程安全保护,而是通过框架计划、最佳实践,以及开发者的代码编写方式来保证安全性。以下是 Spring MVC 保证 Controller 并发安全的方式和开发者应遵照的最佳实践。
1.
无状态计划的控制器
在 Spring MVC 中,单例 Controller 主要依靠于
无状态计划
来实现线程安全。无状态计划是控告制器中不包含任何可变的实例变量,因此所有请求在访问 Controller 时不会共享状态。
示例:无状态控制器
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class SafeController {
@GetMapping("/safe")
@ResponseBody
public String handleRequest(@RequestParam("input") String input) {
// 使用局部变量,不存在线程安全问题
String result = "Processed: " + input;
return result;
}
}
复制代码
说明
:在这个例子中,result 是局部变量,每个请求都有自己的局部变量空间,因此线程之间不会相互影响,从而保证了线程安全。
2.
禁止利用共享的可变实例变量
Spring MVC 中的控制器默认是单例的,因此任何
可变的实例变量
会在并发访问时导致线程安全题目。为此,应避免在控制器中利用任何可变的实例变量,特别是像 List、Map 等集合类型。
示例:避免利用共享的可变实例变量
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class UnsafeController {
private int counter = 0; // 非线程安全的实例变量
@GetMapping("/unsafe")
@ResponseBody
public String handleRequest() {
counter++; // 非线程安全操作
return "Counter: " + counter;
}
}
复制代码
在上面的例子中,counter 是一个实例变量,会被多个请求共享访问。这种情况下,如果有多个线程同时访问 handleRequest,大概会导致 counter 的值出现不同等。因此,
避免利用可变实例变量
是保证线程安全的核心之一。
3.
利用 ThreadLocal 共享数据
如果确实需要在多个方法间共享一些数据,可以利用 ThreadLocal,它能够为每个线程提供独立的变量副本,使数据在线程之间相互隔离,避免并发冲突。
示例:利用 ThreadLocal 实现线程安全的共享数据
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class ThreadLocalController {
private static final ThreadLocal<String> threadLocal = new ThreadLocal<>();
@GetMapping("/threadlocal")
@ResponseBody
public String handleRequest(@RequestParam("input") String input) {
threadLocal.set(input); // 每个线程独立的 threadLocal 副本
try {
return processInput();
} finally {
threadLocal.remove(); // 避免内存泄漏
}
}
private String processInput() {
return "Processed: " + threadLocal.get();
}
}
复制代码
说明
:
ThreadLocal 为每个线程提供独立的变量副本,使每个请求的数据相互独立。
留意在方法调用竣过后调用 threadLocal.remove() 清理数据,以防止内存泄漏。
4.
利用局部变量存储临时数据
局部变量是在方法栈上分配的,线程私有,天然是线程安全的。因此,将方法内的中间状态或临时数据存储在局部变量中可以保证线程安全。
示例:利用局部变量存储中间状态
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class LocalVariableController {
@GetMapping("/localvar")
@ResponseBody
public String handleRequest(@RequestParam("input") String input) {
// 使用局部变量存储临时状态,避免实例变量共享
String result = "Processed: " + input;
return result;
}
}
复制代码
说明
:
result 是局部变量,每个请求都会有自己的 result,因此纵然在并发情况下也是线程安全的。
5.
利用 @Scope("prototype") 使控制器成为多例(不推荐)
固然可以通过 @Scope("prototype") 将控制器作用域设置为多例,每次请求都会创建一个新的控制器实例,避免了线程安全题目,但不推荐这样做,因为它会增加内存和对象创建的开销。
示例:将控制器设为多例
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
@Scope("prototype") // 设置为多例模式
public class PrototypeController {
private int count = 0;
@GetMapping("/prototype")
@ResponseBody
public String handleRequest() {
count++;
return "Request count: " + count;
}
}
复制代码
说明
:
每次请求都会创建一个新的 PrototypeController 实例,count 不会被共享,因此是线程安全的。
但这种做法会增加对象创建的开销和内存利用,因此不推荐在高并发情况下利用。
总结
Spring MVC 保证 Controller 的并发安全主要依靠以下原则和实践:
单例无状态计划
:@Controller 默认是单例,因此控制器应计划为无状态。
避免利用共享的可变实例变量
:控制器中不应包含任何共享的可变实例变量,以免在并发访问时发生线程安全题目。
利用 ThreadLocal 存储线程独立的临时状态
:当需要共享一些临时状态时,利用 ThreadLocal 来隔离数据。
利用局部变量存储临时数据
:将中间状态或临时数据存储在局部变量中,以确保每个请求的隔离性和线程安全。
通过这些计划原则和代码实践,Spring MVC 的 Controller 能够在高并发环境中有用保证线程安全。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
继续阅读请点击广告
回复
使用道具
举报
0 个回复
倒序浏览
返回列表
快速回复
高级模式
B
Color
Image
Link
Quote
Code
Smilies
您需要登录后才可以回帖
登录
or
立即注册
本版积分规则
发表回复
回帖并转播
回帖后跳转到最后一页
发新帖
回复
半亩花草
论坛元老
这个人很懒什么都没写!
楼主热帖
YOLOV5 代码复现以及搭载服务器运行 ...
本周涨粉一倍,我决定再开源一个商超管 ...
APP性能优化
Java集合框架(五)-Collections 和 泛型 ...
安装Python
Spring5——JdbcTemplate笔记
经典Python题目:一个列表或者数组去重 ...
《C++性能优化指南》 linux版代码及原 ...
【Redis】BigKey问题
随机数漫谈
标签云
国产数据库
集成商
AI
运维
CIO
存储
服务器
快速回复
返回顶部
返回列表