Spring 的常見業(yè)務(wù)組件采取單例如何保證線程安全
Spring 作為 IOC 框架,一般來說,Spring 管理的 controller、service、dao 都是單例存在,節(jié)省內(nèi)存和 cpu、提高單機資源利用率(默認單例,配置多例模式使用 scope=prototype),既然是單例,那么如何控制單例被多個線程同時訪問線程安全呢?
首先要理解每個 http 請求到后臺都是一個單獨的線程,線程之間共享同一個進程的內(nèi)存、io、cpu 等資源,但線程棧是線程獨有,線程之間不共享棧資源
其次,bean 分為有狀態(tài) bean 和無狀態(tài) bean,有狀態(tài) bean 即類定義了成員變量,可能被多個線程同時訪問,則會出現(xiàn)線程安全問題;無狀態(tài) bean 每個線程訪問不會產(chǎn)生線程安全問題,因為各個線程棧及方法棧資源都是獨立的,不共享。即是,無狀態(tài) bean 可以在多線程環(huán)境下共享,有狀態(tài) bean 不能
Spring 的 dao、service 層使用的有狀態(tài) bean 如何保證線程安全
Spring 應(yīng)用中 dao、service 一般以單例形式存在,dao、service 中使用的數(shù)據(jù)庫 connection 以及 RequestContextHolder、TransactionSynchronizationManager、LocaleContextHolder 等都是有狀態(tài) bean,而 dao、service 又是單例,如何保證線程安全呢?
答案是使用 threadLocal 進行處理,ThreadLocal 是線程本地變量,每個線程擁有變量的一個獨立副本,所以各個線程之間互不影響,保證了線程安全
SpringMVC 的 controller 并發(fā)訪問
SpringMVC 中的 controller 默認是單例的,那么如果不小心在類中定義了類變量,那么這個類變量是被所有請求共享的,這可能會造成多個請求修改該變量的值,出現(xiàn)與預期結(jié)果不符合的異常。所以如上所述,屬性變量會到值線程安全問題,解決方法包括使用 threadLocal 或不使用屬性變量、配置為多例均可(加鎖控制效率不行)