spring 中的 bean 是線程安全的嗎?
Spring 不保證 bean 的線程安全。
默認 spring 容器中的 bean 是單例的。當單例中存在競態條件,即有線程安全問題。如下面的例子
計數類
package constxiong.interview.threadsafe;
/**
* 計數類
* @author ConstXiong
* @date 2019-07-16 14:35:40
*/
public class Counter {
private int count = 0;
public void addAndPrint() {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(++count);
}
}
spring 配置文件
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
測試類
package constxiong.interview.threadsafe;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class CounterTest {
public static void main(String[] args) {
final ApplicationContext context = new ClassPathXmlApplicationContext("spring_safe.xml");
for (int i = 0; i < 10; i++) {
new Thread(){
@Override
public void run() {
Counter counter = (Counter)context.getBean("counter");
for (int j = 0; j < 1000; j++) {
counter.addAndPrint();
}
}
}.start();
}
}
}
打印結果開頭和結尾
1無錫人流費用 http://www.xasgfk120.com/
5
7
4
2
6
3
8
9
.
.
.
9818
9819
9820
9821
9822
9823
9824
9825
期望打印出的最大值應該是 10000
修改 spring 配置文件,把 bean 的作用域改為 prototype
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
測試結果輸出10個 1000
即每個線程都創建了一個 Counter 對象,線程內獨自計數,不存在線程安全問題。但是不是我們想要的結果,打印出 10000。
所以 spring 管理的 bean 的線程安全跟 bean 的創建作用域和 bean 所在的使用環境是否存在競態條件有關,spring 並不能保證 bean 的線程安全。
