Spring bean的线程安全问题
?? 最近参与的一个项目中,大量使用了spring注入bean,出现了线程安全问题,发了很长的时间才定位出来,在此记录下,用例子模拟下。
<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans"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-3.1.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context-3.1.xsd"><context:annotation-config /><context:component-scan base-package="unsafe"/></beans>
?
模拟的服务类源码
package unsafe;import org.springframework.beans.factory.config.BeanDefinition;import org.springframework.context.annotation.Scope;import org.springframework.stereotype.Component;// 这里模拟Action需要使用的service层处理类// 每1个http请求,struts2都会为之创建一个新的处理线程,该线程调用service层的方法完成处理逻辑@Component("studentService")//@Scope(BeanDefinition.SCOPE_PROTOTYPE)public class StudentService{ private int age = 0; public void testAge() { String name = Thread.currentThread().getName(); System.out.println(name + "," + "age before change is:" + age); age += 10; System.out.println(name + "," + "age after change is:" + age); }}
?
模拟的http线程
package unsafe;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;public class TestThread extends Thread{ private StudentService student = null; public TestThread(StudentService student) { this.student = student; } @Override public void run() { student.testAge(); } public static void main(String[] args) { // 这里模仿spring容器 ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml"); // 这里模拟浏览器发的1个http请求,对应的struts2处理线程 startNewThread(context); // 这里模拟浏览器发的1个http请求,对应的struts2处理线程 startNewThread(context); } private static void startNewThread(ApplicationContext context) { StudentService student = (StudentService) context.getBean("studentService"); TestThread t = new TestThread(student); t.start(); }}
?
注意:如果一个bean类有成员变量,要引起关注。如果这个bean配置的是单例模式id,这个变量就会被多线程共享,很容易出现线程安全问题。
?