Spring的多线程


Spring框架里的bean,或者说组件,获取实例的时候都是默认的单例模式,这是在多线程开发的时候要尤其注意的地方。

每一个request过来,系统都会调用原有的instance去处理,这样导致有俩个结果:

一是不用每次创建Controller
二是减少了对象创建和垃圾的收集的时间

当多用户同时请求一个服务的时候,容器会给每一个请求分配一个线程,并发执行该业务逻辑,如果逻辑中有处理该单列的成员属性时候,必须考虑线程同步。

考虑如下代码:

@RequestMapping("/user")
@Controller
Class UserController
{
@Resource
UserService userService;

@RequestMapping("/add")
public void testA(User user){
userService.add(user);
}

@RequestMapping("/get")
public void testA(int id){
userService.get(id);
}
}

@Service("userService")
Class UserService{

public static Map<Integer,User> usersCache = new HashMap<String,User>();

public void add(User user){
usersCache.put(user.getId(),user);
}

public void get(int id){
usersCache.get(id);
}

}

此段代码,usersCache对象就是线程不安全的。因为它是静态的全局共享对象。如果有多个线程同时调用add方法,可能会发生用户对象被覆盖的情况,也就是id对应对象不一致,这是多线程编程中最常发生的事情。

Spring 框架维护 Controller Dao Service(注入) 的(方法)线程安全。

SpringMvc和Servlet都是方法的线程安全,在类方法声明的公有和私有变量不是线程安全的。
如果用多个线程请求同一个Controller类中的同一个方法,线程不会阻塞。

 

Spring 框架使用了大量的ThreadLocal进制同步线数据 (空间换时间)

ThreadLocal 会为每一个线程提供一个独立的变量副本:

class SimpleThreadLocal {
private MapvalueMap = Collections.synchronizedMap(new HashMap());
public voidset(Object newValue) {
valueMap.put(Thread.currentThread(), newValue);//①键为线程对象,值为本线程的变量副本
}
publicObject get() {
Thread currentThread = Thread.currentThread();
Object o = valueMap.get(currentThread);// ②返回本线程对应的变量
if (o == null &&!valueMap.containsKey(currentThread)) {// ③如果在Map中不存在,放到Map
// 中保存起来。
o = initialValue();
valueMap.put(currentThread, o);
}
return o;
}
public voidremove() {
valueMap.remove(Thread.currentThread());
}
publicObject initialValue() {
return null;
}
}

 

线程安全问题都是由全局变量及静态变量引起的。 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM