目录
前言
Spring
容器中的 bean
是否线程安全,容器本身并没有提供 bean 的线程安全策略
,因此可以说 Spring
容器中的 bean
本身不具备线程安全的特性,但是具体还是要结合具体 Scope
作用域的去研究
Spring
中的 bean
作用域
singleton
:单例,默认的作用域prototype
:原型,每次获取该bean
都会创建一个新的bean
request
:每次HTTP
请求会产生一个新的bean
,该bean
仅在当前request
会话内有效session
:每次HTTP
请求会产生一个新的bean
,该bean
仅在当前session
会话内有效
线程安全这个问题,要从单例与原型 bean
分别进行说明
原型 bean
bean
的作用域为原型prototype
时,当存在bean
的非静态的成员变量
时,无论你使用不使用非静态的成员变量,此时bean
是线程安全的bean
的作用域为原型prototype
时,当存在bean
的静态的成员变量
时,并且调用该bean
的方法会使变量值发生改变时,此时bean
是线程不安全的
单例 bean
对于单例 bean
所有线程都共享一个单例 bean
,因此是存在资源的竞争,无论该 bean
存不存在成员变量(静态与非静态),该 bean
都是非线程安全的
Spring
中的 Controller,Service
怎么保证线程的安全
默认情况下,Controller,Service
的 bean
都是单例的;既然要保证线程安全,也就是当前的 bean
是有成员变量属性的
非静态的成员变量
@Slf4j
@Controller
public class ScopeTestController {
private int num = 0;
@GetMapping(path = "/testScope1")
@ResponseBody
public int testScope1() {
int a = ++num;
log.info("a 的值为:" + a);
return a;
}
@GetMapping(path = "/testScope2")
@ResponseBody
public int testScope2() {
int a = ++num;
log.info("a 的值为:" + a);
return a;
}
}
我们依次访问 http://localhost:8080/testScope1
,http://localhost:8080/testScope2
,结果如下
结论:默认情况下, Spring
中单例 bean
如果存在非静态的成员变量属性,并且调用该 bean
的方法会使该 bean
的变量属性值发生改变时,此时我们可以认为该 bean
是线程不安全的
静态的成员变量
@Slf4j
@Controller
public class ScopeTestController {
private static int num = 0;
@GetMapping(path = "/testScope1")
@ResponseBody
public int testScope1() {
int a = ++num;
log.info("a 的值为:" + a);
return a;
}
@GetMapping(path = "/testScope2")
@ResponseBody
public int testScope2() {
int a = ++num;
log.info("a 的值为:" + a);
return a;
}
}
我们依次访问 http://localhost:8080/testScope1
,http://localhost:8080/testScope2
,结果如下
结论:默认情况下, Spring
中单例 bean
如果存在静态的成员变量属性,并且调用该 bean
的方法会使该 bean
的变量属性值发生改变时,此时我们可以认为该 bean
是线程不安全的
怎么保证线程的安全
不要在 Controller,Service
中定义成员变量,在 Controller,Service
中可以使用 ThreadLocal
来定义线程的局部变量
使用注解 @Scope(scopeName = "prototype")
给 ScopeTestController
这个类上添加注解 @Scope(scopeName = "prototype")
非静态的成员变量
结果如下
结论: bean
的作用域为原型 prototype
时,当存在 bean
的非静态的成员变量时,无论你使用不使用非静态的成员变量,此时 bean
是线程安全的
静态的成员变量
在此情况下,虽然添加了注解 @Scope(scopeName = "prototype")
结果如下
结论: bean
的作用域为原型 prototype
时,当存在 bean
的静态的成员变量时,并且调用该 bean
的方法会使变量值发生改变时,此时 bean
是线程不安全的