当前位置: 首页 > 创领中心 > 网络优化

面试官 聊聊Spring中Bean的线程安保疑问

  • 网络优化
  • 2024-11-15

自动状况下,Spring Boot 中的 Bean 是非线程安保的。这是由于,自动状况下 Bean 的作用域是单例形式,那么此时,一切的恳求都会共享同一个 Bean 实例,这象征着这个 Bean 实例,在多线程下或许被同时修正,那么此时它就会出现线程安保疑问。

并不是,单例 Bean 分为以下两种类型:

所以说: 有形态的单例 Bean 是非线程安保的,而有形态的 Bean 是线程安保的

有形态的 Bean 指的是不存在成员变量,或只要查问操作,没有修正操作,它的成功示例代码如下:

import org.springframework.stereotype.Service;@Servicepublic class StatelessService {public void doSomeTask() {// 口头义务}}

有成员变量,并且存在对成员变量的修正操作,如下代码所示:

import org.springframework.stereotype.Service;@Servicepublic class UserService {private int count = 0;public void incrementCount() {count++; // 非原子操作,并发存在线程安保疑问}public int getCount() {return count;}}

想要保障有形态 Bean 的线程安保,可以从以下几个方面来成功:

详细成功如下。

实现代码如下:

import org.springframework.stereotype.Service;@Servicepublic class UserService {private ThreadLocal<Integer> count = ThreadLocal.withInitial(() -> 0);public void incrementCount() {count.set(count.get() + 1);}public int getCount() {return count.get();}}

经常使用 ThreadLocal 须要留意一个疑问,在用完之后记得调用 ThreadLocal 的 remove 方法,不然会出现内存走漏疑问。

锁机制中最繁难的是经常使用 synchronized 润色方法,让多线程口头此方法时排队口头,这样就不会有线程安保疑问了,如下代码所示:

import org.springframework.stereotype.Service;@Servicepublic class UserService {private int count = 0;public synchronized void incrementCount() {count++; // 非原子操作,并发存在线程安保疑问}public int getCount() {return count;}}

(3)设置为原型作用域

原型作用域经过 @Scope("prototype") 来设置,示意每次恳求时都会生成一个新对象(也就没有线程安保疑问了),如下代码所示:

import org.springframework.stereotype.Service;@Service@Scope("prototype")public class UserService {private int count = 0;public void incrementCount() {count++; // 非原子操作,并发存在线程安保疑问}public int getCount() {return count;}}

(4)经常使用线程安保容器

咱们可以经常使用线程安保的容器,例如 AtomicInteger 来代替 int,从而保障线程安保,如下代码所示:

import org.springframework.stereotype.Service;import java.util.concurrent.atomic.AtomicInteger;@Servicepublic class UserService {private AtomicInteger count = new AtomicInteger(0);public void incrementCount() {count.incrementAndGet();}public int getCount() {return count.get();}}

实践上班中如何保障线程安保?

实践上班中,通常会依据详细的业务场景来选用适合的线程安保打算,然而以上处置线程安保的打算中,ThreadLocal 和原型作用域会经常使用更多的资源,占用更多的空间来保障线程安保,所以在经常使用时通常不会作为最佳思考打算。

而锁机制和线程安保的容器通常会优先思考,但须要留意的是 AtomicInteger 底层是失望锁 CAS 成功的,因此它存在失望锁的典型疑问 ABA 疑问(假设有形态的 Bean 中既有 ++ 操作,又有 -- 操作时,或许会出现 ABA 疑问),此时就要经常使用锁机制,或 AtomicStampedReference 来处置 ABA 疑问了。

单例形式的 Bean 并不必定都是非线程安保的,其中有形态的 Bean 是存在线程安保疑问的。实践上班中通常会经常使用锁机制(synchronized 或 ReentrantLock)或线程安保的容器来处置 Bean 的线程安保疑问,但详细经常使用哪种打算,还要联合详细业务场景来定。

  • 关注微信

本网站的文章部分内容可能来源于网络和网友发布,仅供大家学习与参考,如有侵权,请联系站长进行删除处理,不代表本网站立场,转载联系作者并注明出处:https://clwxseo.com/wangluoyouhua/8867.html

猜你喜欢

热门资讯

关注我们

微信公众号