面试官:Spring创建好的单例对象存在线程安全问题吗?
点击关注公众号,实用技术文章及时了解
来源:blog.csdn.net/jdk_wangtaida/
article/details/88738228
前言
这是我在一次面试中被问到过的问题,但是当时我回答的并不是太好,最近在学习多线程知识的时候又对这个问题有了新的理解,所以这篇文章主要讲解下我对个问题的理解。
正文
一、理解这个问题前,你需要先知道几个知识点
1.spring的bean作用域都有哪些?默认是哪个?
默认的是:单例 singleton
2.创建单例的方式是否线程安全与使用已经创建好的单例对象是否线程安全是两个问题
①常见创建单例的方式懒汉式和饿汉式
懒汉式(不安全写法)
public class Singleton{ private Singleton(){}private static Singleton singleton = null; //不建立对象public static Singleton getInstance(){if(singleton == null) { //先判断是否为空singleton = new Singleton (); //懒汉式做法 }return singleton ;}
}
饿汉式
public class Singleton{ public Singleton(){}private static Singleton singleton = new Singleton(); //建立对象public static Singleton getInstance(){return singleton ;//直接返回单例对象 }}
这两种创建方式中,懒汉式在多线程环境下就是线程不安全的,假设有线程1和线程2两个线程,线程1在判断if(singleton == null)
的时候,突然失去cpu的执行权,而线程2获得了cpu的执行权,执行了getInstance()方法,创建了个对象,但是这个事情线程1并不知道,线程1重新获得cpu的执行权时,判断if(singleton == null)
结果是null,所以又去创建了对象,那么这样就会出现破坏单例的情况,有多余的对象,所以线程是不安全的,解决方案之一就是加锁,代码如下
懒汉式(安全写法)
public class Singleton{ private Singleton(){}private static Singleton singleton = null; //不建立对象public static synchronized Singleton getInstance(){if(singleton == null) { //先判断是否为空singleton = new Singleton (); //懒汉式做法 }return singleton ;}
}
②在spring的框架里,对象是交给spring容器创建的,spring的创建单例的方式既不是懒汉式也不是饿汉式,是单例注册表模式实现单例模式的,感兴趣的可以看这篇文章:https://blog.csdn.net/u012794505/article/details/80926823
,这种创建单例模式的方式是线程安全的。
③怎么判断使用已经创建好的单例对象是否线程安全
看这个单例里有没有全局变量(全局变量就是成员变量,成员变量又分实例变量和静态变量)
如果有全局变量,看它是不是只可以读取而不能写入(有没有发布set方法)
如果满足上面两个条件,那么这个单例就是不安全的。
二、spring的单例模式与线程安全
1.spring框架里的bean获取实例的时候都是默认单例模式,所以在多线程开发里就有可能会出现线程不安全的问题。当多个用户同时请求一个服务器时,容器(tomcat)会给每一个请求分配一个线程,这时多个线程会并发执行该请求所对应的业务逻辑(controller里的方法),此时就要注意啦,如果controller(是单例对象)里有全局变量并且又是可以修改的,那么就需要考虑线程安全的问题。解决方案有很多,比如设置@scope("prototype")
为多例模式,为每个线程创建一个controller,还可以使用ThreadLocal。
2.其实spring的源码里比如RequestContextHolder
、TransactionSynchronizationManager
、LoxaleContextHolder
等这些对象创建方式也是单例,底层就是用ThreadLocal处理的。ThreadLocal基本实现思路是:它会为每个线程提供一个独立的变量副本,从而隔离了多个线程对数据的访问冲突,因为每个线程都拥有自己的变量副本,从而也就没必要对该变量进行同步啦。
3.在ssh或ssm框架里的service或dao对象虽然也是单例模式,但正如上面分析的,他们没有可修改的全局变量,所以在多线程环境下也是安全的。
4.其实在很多文章中对于spring的单例模式与线程安全会提到一个概念有状态对象和无状态对象,无状态对象在多线程环境下是线程安全的,有状态的对象则不是,其实这个字面的意思是比较对的,因为这个对象如果无法存储数据,也就不会出现多个线程操作共享数据的情况,自然安全,概念如下
有状态就是有数据存储功能。有状态对象(Stateful Bean),就是有实例变量的对象,可以保存数据,是非线程安全的。在不同方法调用间不保留任何状态。
无状态就是一次操作,不能保存数据。无状态对象(Stateless Bean),就是没有实例变量的对象.不能保存数据,是不变类,是线程安全的。
但是很多文章举的无状态对象的例子我认为不合理。比如:https://blog.csdn.net/bingjing12345/article/details/9794945
,因为如果这个对象没有set放方法只是可读,其实也是安全的。
public class StatefulBean { public int state; // 由于多线程环境下,user是引用对象,是非线程安全的 public User user; public int getState() { return state; } public void setState(int state) { this.state = state; } public User getUser() { return user; } public void setUser(User user) { this.user = user; }
}
总结
其实你越去了解框架底层的实现原理,你越会为这个框架的思想而着迷,你会感慨框架笔者的想法是多么的奇妙,多么的周全,多一字嫌多,少一字嫌少。
●【练手项目】基于SpringBoot的ERP系统,自带进销存+财务+生产功能
●分享一套基于SpringBoot和Vue的企业级中后台开源项目,代码很规范!
●能挣钱的,开源 SpringBoot 商城系统,功能超全,超漂亮!
PS:因为公众号平台更改了推送规则,如果不想错过内容,记得读完点一下“在看”,加个“星标”,这样每次新文章推送才会第一时间出现在你的订阅列表里。点“在看”支持我们吧!
面试官:Spring创建好的单例对象存在线程安全问题吗?相关推荐
- spring框架中的单例Beans是线程安全的么?
看到这样一个问题:spring框架中的单例Beans是线程安全的么? Spring框架并没有对单例bean进行任何多线程的封装处理.关于单例bean的线程安全和并发问题需要开发者自行去搞定.但实际上, ...
- Spring框架中的单例Beans是线程安全的么
看到这样一个问题:Spring框架中的单例Beans是线程安全的么? Spring框架并没有对单例bean进行任何多线程的封装处理.关于单例bean的线程安全和并发问题需要开发者自行去搞定.但实际上, ...
- Spring 框架中的单例Beans 是线程安全的么?
Spring 框架并没有对单例bean 进行任何多线程的封装处理.关于单例bean 的线程安全和并发问题需要开发者自行去搞定.但实际上,大部分的Spring bean 并没有可变的状态(比如Servi ...
- Spring框架中的单例Bean是线程安全的吗?
首先直接给出答案:不是线程安全的 一.分析问题 证明不是线程安全的案例如下: public class Student {private String stuName;public String re ...
- Spring框架中的单例Bean是线程安全的么?
答: 不是安全的. Spring中的Bean默认是单例模式的,框架并没有对bean进行多线程的封装处理. 注:单例bean是指IOC容器中就只有这么一个bean,是全局共享的,有多少个线程来访问用的都 ...
- 单例带来的线程安全问题
其实最初对于单例的线程安全问题一直一知半解,在我们大多使用spring的项目来说,spring管理bean默认是单例的,那么我们的业务逻辑也会是单例的也就是service是单例的,那么这是servic ...
- Spring框架中的单例Bean是线程安全的吗
Sp
- 【Kotlin】Kotlin 单例 ( 懒汉式 与 恶汉式 | Java 单例 | Kotlin 单例 | 对象声明 | 伴生对象 | get 方法 | ? 与 !! 判空 )
文章目录 I . 单例的懒汉式与恶汉式 II . Java 中的懒汉式与恶汉式 III . Kotlin 中对应 Java 的懒汉式与恶汉式 IV . Kotlin 对象 ( object ) 声明 ...
- Spring中bean的单例与多例
Spring中bean的单例与多例 前言 Spring中单例与多例 如何配置单例/多例 单例/多例Bean的使用事项 总结 前言 之前其实已经学习过对于单例模式的使用单例模式讲解,也用过一段时间的Sp ...
最新文章
- Java 强引用与软引用以及弱引用,虚引用
- CTFshow php特性 web145
- 骑士周游算法 c语言_C语言经典算法04--骑士走棋盘(骑士旅游:Knight tour)
- [C++11]基于范围的for循环
- JAVA 技术类分享(一)
- linux-centos7 常用的基本命令--文件内容查看、硬链接和软链接
- 转向与重定向的联系与区别
- Java 算法 等差数列
- 梦笔记2022-2-1
- matlab直流电机转速 电流双闭环,转速 电流双闭环直流调速系统的课程设计(MATLAB Simulink)...
- MVC jQuery表单验证
- 《甄嬛传》计谋汇总, 本文忠实于《后宫 甄嬛传》第1本~第7本+番外原文,而非电视剧。
- 用Python写的水仙花数程序,感觉这个也比较好懂
- osm服务器 显示乱码,怎样获得osm上的行政区划shp文件
- 一种网格去噪算法(基于平均面法向的均值滤波)
- vuepress-theme-reco + Github Actions 构建静态博客,部署到第三方服务器
- python01g内存读取10g文件并排序_将大文件逐行读取到Python2.7中时的内存使用
- 向上滚动 终端_终端 - 如何在Linux控制台上向上/向下滚动?
- 3.1 机器学习模型
- redis详解(三)-- 面试题
热门文章
- 不敢摔!三星Galaxy Fold换屏费用可以入手一部华为Mate 30了
- 美图回应与华为合作:华为没有使用美图的任何影像技术
- 拼多多董事会变更:董事6人变5人 张震不再出任
- 雷军:小米9完全开放购买 全面现货供应
- 整天做办公室的我们要注意饮食啊
- R40使用GPIO中断实现按键功能【原创】
- 嵌入式linux的tftp配置[ZT]
- couldn't find libweibosdkcore.so
- Android实现图片的高效批量加载
- kasp技术原理_KASP基因型测定技术在各个学科的应用实践(内附官方重要资料)...