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