spring中的bean是线程安全的吗?

内容摘要
Spring 不保证 bean 的线程安全。默认 spring 容器中的 bean 是单例的。当单例中存在竞态条件,即有线程安全问题。如下面的例子计数类package constxiong.interview.threadsa
文章正文

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 配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="/d/file/p/20221028/"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:context="/d/file/p/20221028/"
	xsi:schemaLocation="
		/d/file/p/20221028/ 
		/d/file/p/20221028//spring-beans.xsd
	    /d/file/p/20221028/
        /d/file/p/20221028//spring-context.xsd">
        
	<bean id="counter" class="constxiong.interview.threadsafe.Counter" />
	
</beans>

测试类

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
5
7
4
2
6
3
8
9
.
.
.
9818
9819
9820
9821
9822
9823
9824
9825

期望打印出的最大值应该是 10000

修改 spring 配置文件,把 bean 的作用域改为 prototype

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="/d/file/p/20221028/"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:context="/d/file/p/20221028/"
	xsi:schemaLocation="
		/d/file/p/20221028/ 
		/d/file/p/20221028//spring-beans.xsd
	    /d/file/p/20221028/
        /d/file/p/20221028//spring-context.xsd">
	<bean id="counter" class="constxiong.interview.threadsafe.Counter" scope="prototype"/>
</beans>

测试结果输出10个 1000

java-11.png即每个线程都创建了一个 Counter 对象,线程内独自计数,不存在线程安全问题。但是不是我们想要的结果,打印出 10000。

所以 spring 管理的 bean 的线程安全跟 bean 的创建作用域和 bean 所在的使用环境是否存在竞态条件有关,spring 并不能保证 bean 的线程安全。

代码注释
[!--zhushi--]

作者:喵哥笔记

IDC笔记

学的不仅是技术,更是梦想!