系列十八、Spring bean线程安全问题

一、概述

        我们知道Spring中的bean,默认情况下是单例的,那么Spring中的bean是线程安全的吗?这个需要分情况考虑,bean中是否存在成员变量?bean中的成员变量是怎么处理的?...,针对bean的状态会有不同的处理方案:

        情况一:bean是单例的;

        情况二:bean是多例的(不会存在线程安全问题);

出现线程安全问题的原因:单实例bean中存在成员变量,并且有对这个bean进行读写的操作,因此出现了线程安全的问题。

二、演示Spring bean存在线程安全

2.1、UserService

/*** @Author : 一叶浮萍归大海* @Date: 2023/11/26 14:55* @Description: */
@Service
public class UserService {private String username;public String welcome(String name) {username = "welcome " + name;try {Thread.sleep(100);} catch (Exception e) {e.printStackTrace();}return username;}}

2.2、MySpringConfig

/*** @Author : 一叶浮萍归大海* @Date: 2023/11/23 15:29* @Description:*/
@Configuration
@ComponentScan(basePackages = {"org.star"})
public class MySpringConfig {}

2.3、AopFullAnnotationMainApp

/*** @Author : 一叶浮萍归大海* @Date: 2023/11/23 15:14* @Description:*/
@Slf4j
public class AopFullAnnotationMainApp {public static void main(String[] args) {AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MySpringConfig.class);UserService userService = context.getBean(UserService.class);Random r = new Random();String[] nameArray = new String[]{"张三", "李四", "王五", "赵六", "钱七"};for (int i = 1; i <= 5; i++) {new Thread(() -> {int index = r.nextInt(5);String name = nameArray[index];log.info("当前线程:{},当前索引:{},当前name的值:{},当前取出的值:{}", Thread.currentThread().getName(), index, name, userService.welcome(name));}, "线程" + i).start();}}}

三、解决方法

        上面代码演示了Spring中的bean的确存在着线程安全问题,出现问题我们要解决问题,针对Spring中bean中存在的线程安全,我们可以通过以下方式进行解决:

        方案一:将成员变量修改为局部变量(单例bean);

        方案二:使用ThreadLocal(单例bean);

        方案三:使用同步锁synchronized(单例bean);

        方案四:将单例bean设置为多例的;

        案例代码如下:

3.1、将成员变量修改为局部变量(单例bean)

3.1.1、UserService2

/*** @Author : 一叶浮萍归大海* @Date: 2023/11/26 14:55* @Description: 单例bean线程不安全(解决方式一:将成员变量修改为局部变量)*/
@Service
public class UserService2 {public String welcome(String name) {String username = "welcome " + name;try {Thread.sleep(100);} catch (Exception e) {e.printStackTrace();}return username;}}

3.1.2、MySpringConfig(同上)

3.1.3、AopFullAnnotationMainApp 

/*** @Author : 一叶浮萍归大海* @Date: 2023/11/23 15:14* @Description:*/
@Slf4j
public class AopFullAnnotationMainApp {public static void main(String[] args) {AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MySpringConfig.class);UserService2 userService2 = context.getBean(UserService2.class);Random r = new Random();String[] nameArray = new String[]{"张三", "李四", "王五", "赵六", "钱七"};for (int i = 1; i <= 5; i++) {new Thread(() -> {int index = r.nextInt(5);String name = nameArray[index];log.info("当前线程:{},当前索引:{},当前name的值:{},当前取出的值:{}", Thread.currentThread().getName(), index, name, userService2.welcome(name));}, "线程" + i).start();}}
}

3.2、使用ThreadLocal(单例bean)

3.2.1、UserService3

/*** @Author : 一叶浮萍归大海* @Date: 2023/11/26 14:55* @Description: 单例bean线程不安全(解决方式二:使用ThreadLocal)*/
@Service
public class UserService3 {private ThreadLocal<String> threadLocal = new ThreadLocal<>();public String welcome(String name) {threadLocal.set("welcome" + name);try {Thread.sleep(100);} catch (Exception e) {e.printStackTrace();}return threadLocal.get();}}

3.2.2、MySpringConfig(同上)

3.2.4、AopFullAnnotationMainApp

/*** @Author : 一叶浮萍归大海* @Date: 2023/11/23 15:14* @Description:*/
@Slf4j
public class AopFullAnnotationMainApp {public static void main(String[] args) {AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MySpringConfig.class);UserService3 userService3 = context.getBean(UserService3.class);Random r = new Random();String[] nameArray = new String[]{"张三", "李四", "王五", "赵六", "钱七"};for (int i = 1; i <= 5; i++) {new Thread(() -> {int index = r.nextInt(5);String name = nameArray[index];log.info("当前线程:{},当前索引:{},当前name的值:{},当前取出的值:{}", Thread.currentThread().getName(), index, name, userService3.welcome(name));}, "线程" + i).start();}}
}

3.3、使用同步锁synchronized(单例bean)

3.3.1、UserService4

/*** @Author : 一叶浮萍归大海* @Date: 2023/11/26 14:55* @Description: 单例bean线程不安全(解决方式三:使用同步锁synchronized)*/
@Service
public class UserService4 {private String username;public synchronized String welcome(String name) {username = "welcome " + name;try {Thread.sleep(100);} catch (Exception e) {e.printStackTrace();}return username;}}

3.3.2、MySpringConfig(同上)

3.3.3、AopFullAnnotationMainApp 

/*** @Author : 一叶浮萍归大海* @Date: 2023/11/23 15:14* @Description:*/
@Slf4j
public class AopFullAnnotationMainApp {public static void main(String[] args) {AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MySpringConfig.class);UserService4 userService4 = context.getBean(UserService4.class);Random r = new Random();String[] nameArray = new String[]{"张三", "李四", "王五", "赵六", "钱七"};for (int i = 1; i <= 5; i++) {new Thread(() -> {int index = r.nextInt(5);String name = nameArray[index];log.info("当前线程:{},当前索引:{},当前name的值:{},当前取出的值:{}", Thread.currentThread().getName(), index, name, userService4.welcome(name));}, "线程" + i).start();}}
}

3.4、将单例bean设置为多例的

3.4.1、UserService5

/*** @Author : 一叶浮萍归大海* @Date: 2023/11/26 14:55* @Description: 单例bean线程不安全(解决方式四:将单例bean设置为多例的)*/
@Scope("prototype")
@Service
public class UserService5 {private String username;public String welcome(String name) {username = "welcome " + name;try {Thread.sleep(100);} catch (Exception e) {e.printStackTrace();}return username;}}

3.4.2、MySpringConfig(同上)

3.4.3、AopFullAnnotationMainApp 

/*** @Author : 一叶浮萍归大海* @Date: 2023/11/23 15:14* @Description:*/
@Slf4j
public class AopFullAnnotationMainApp {public static void main(String[] args) {AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MySpringConfig.class);Random r = new Random();String[] nameArray = new String[]{"张三", "李四", "王五", "赵六", "钱七"};for (int i = 1; i <= 5; i++) {new Thread(() -> {UserService5 userService5 = context.getBean(UserService5.class);int index = r.nextInt(5);String name = nameArray[index];log.info("当前线程:{},当前索引:{},当前name的值:{},当前取出的值:{}", Thread.currentThread().getName(), index, name, userService5.welcome(name));}, "线程" + i).start();}}
}

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/221679.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

FaceChain集成最强开源SDXL,生成人像质感拉满!

一、介绍 FaceChain&#xff0c;一款备受欢迎的AI写真开源项目&#xff0c;目前已与最强大的开源生图模型SDXL完美融合&#xff01;这将为用户带来前所未有的高质量AI写真体验。 FaceChain是一个可以用来打造个人数字形象的深度学习模型工具。用户仅需要提供最低一张照片即可获…

vue.js如何根据后台返回来的图片url进行图片下载

原创/朱季谦 最近在做一个前端vue.js对接的功能模块时&#xff0c;需要实现一个下载图片的功能&#xff0c;后台返回来的是一串图片url&#xff0c;试了很多种方法&#xff0c;发现点击下载时出来的效果&#xff0c;都是跳到一个新的图片网页&#xff0c;后来经过一番琢磨&…

『Linux升级路』基础开发工具——make/Makefile

&#x1f525;博客主页&#xff1a;小王又困了 &#x1f4da;系列专栏&#xff1a;Linux &#x1f31f;人之为学&#xff0c;不日近则日退 ❤️感谢大家点赞&#x1f44d;收藏⭐评论✍️ 目录 一、认识make/Makefile &#x1f4d2;1.1make/Makefile的优点 &#x1f4d2;…

基于C#实现鸡尾酒排序(双向冒泡排序)

通俗易懂点的话&#xff0c;就叫“双向冒泡排序”。 冒泡是一个单向的从小到大或者从大到小的交换排序&#xff0c;而鸡尾酒排序是双向的&#xff0c;从一端进行从小到大排序&#xff0c;从另一端进行从大到小排序。 从图中可以看到&#xff0c;第一次正向比较&#xff0c;我们…

交流回馈负载的主要工作方式

交流回馈负载是一种电力电子装置&#xff0c;其主要工作方式是将电能从交流电源转换为直流电&#xff0c;然后再将直流电转换为交流电。这种转换过程是可逆的&#xff0c;因此可以用于调节电网的电压和频率&#xff0c;提高能源利用效率&#xff0c;减少能源浪费。 交流回馈负载…

浅谈智能照明控制系统在建筑电气工程中的应用

贾丽丽 安科瑞电气股份有限公司 上海嘉定 201801 摘要&#xff1a;建筑电气工程是项目工程中的重要组成部分&#xff0c;其对技术、电气设备及系统的要求较高。在信息化技术不断深入推广的新时期&#xff0c;建筑电气工程中的照明系统获得新的发展契机&#xff0c;为了满足现…

制造业工厂如何选择生产管理MES系统?

一、技术架构 虽然绝大多数的用户不会关心MES设计的技术架构&#xff0c;但如果是好的MES系统&#xff0c;需首先必须具备先进的技术支撑&#xff0c;只有先进的开发平台配合上可配置的模块模组&#xff0c;才可快速构建出符合不同用户场景的业务功能。 试想一下&#xff1a;在…

Portraiture4.1.2最新汉化免费版磨皮插件

关于PS修图插件&#xff0c;相信大家都有安装过使用过&#xff0c;而且还不止安装了一款&#xff0c;比如最为经典的DR5.0人像精修插件&#xff0c;Retouch4me11合1插件&#xff0c;Portraiture磨皮插件&#xff0c;这些都是人像精修插件中的领跑者。 其中 Portraiture 刚刚升…

Nginx常见的中间件漏洞

目录 1、Nginx文件名逻辑漏洞 2、Nginx解析漏洞 3、Nginx越权读取缓存漏洞 这里需要的漏洞环境可以看&#xff1a;Nginx 配置错误导致的漏洞-CSDN博客 1、Nginx文件名逻辑漏洞 该漏洞利用条件有两个&#xff1a; Nginx 0.8.41 ~ 1.4.3 / 1.5.0 ~ 1.5.7 php-fpm.conf中的s…

探索深度学习:从理论到实践的全面指南

探索深度学习&#xff1a;从理论到实践的全面指南 摘要&#xff1a; 本文旨在提供一个关于深度学习的全面指南&#xff0c;带领读者从理论基础到实践应用全方位了解这一技术。我们将介绍深度学习的历史、基本原理、常用算法和应用场景&#xff0c;并通过Python代码示例和Tens…

Vscode工具使用指南

通用 快捷键文件 / 编辑查找 / 替换窗口插件主题 连接linux 快捷键 文件 / 编辑 新建文件&#xff1a;CtrlN放大或缩小&#xff1a;Ctrl /-代码行缩进&#xff0c;展开&#xff1a;Ctrl[ 和 Ctrl]在当前行下方插入一行&#xff1a;CtrlEnter在当前行上方插入一行&#xff1a;…