1. 程式人生 > >Spring中的執行緒安全性

Spring中的執行緒安全性

一:Spring與執行緒安全

Spring作為一個IOC/DI容器,幫助我們管理了許許多多的“bean”。但其實,Spring並沒有保證這些物件的執行緒安全,需要由開發者自己編寫解決執行緒安全問題的程式碼。

Spring對每個bean提供了一個scope屬性來表示該bean的作用域。它是bean的生命週期。例如,一個scope為singleton的bean,在第一次被注入時,會建立為一個單例物件,該物件會一直被複用到應用結束。

 ●  singleton:預設的scope,每個scope為singleton的bean都會被定義為一個單例物件,該物件的生命週期是與Spring IOC容器一致的(但在第一次被注入時才會建立)。
 ●  prototype:bean被定義為在每次注入時都會建立一個新的物件。
 ●  request:bean被定義為在每個HTTP請求中建立一個單例物件,也就是說在單個請求中都會複用這一個單例物件。
 ●  session:bean被定義為在一個session的生命週期內建立一個單例物件。
 ●  application:bean被定義為在ServletContext的生命週期中複用一個單例物件。
 ●  websocket:bean被定義為在websocket的生命週期中複用一個單例物件。

我們交由Spring管理的大多數物件其實都是一些無狀態的物件,這種不會因為多執行緒而導致狀態被破壞的物件很適合Spring的預設scope,每個單例的無狀態物件都是執行緒安全的(也可以說只要是無狀態的物件,不管單例多例都是執行緒安全的,不過單例畢竟節省了不斷建立物件與GC的開銷)

無狀態的物件即是自身沒有狀態的物件,自然也就不會因為多個執行緒的交替排程而破壞自身狀態導致執行緒安全問題。無狀態物件包括我們經常使用的DO、DTO、VO這些只作為資料的實體模型的貧血物件,還有Service、DAO和Controller,這些物件並沒有自己的狀態,它們只是用來執行某些操作的。例如,每個DAO提供的函式都只是對資料庫的CRUD,而且每個資料庫Connection都作為函式的區域性變數(區域性變數是在使用者棧中的,而且使用者棧本身就是執行緒私有的記憶體區域,所以不存線上程安全問題),用完即關(或交還給連線池)。

有人可能會認為,我使用request作用域不就可以避免每個請求之間的安全問題了嗎?這是完全錯誤的,因為Controller預設是單例的,一個controller物件是會被多個執行緒共享的,這就又回到了執行緒的安全問題。當然,你也可以把Controller的scope改成prototype,實際上Struts2就是這麼做的,但有一點要注意,Spring MVC對請求的攔截粒度是基於每個方法的,而Struts2是基於每個類的,所以把Controller設為多例將會頻繁的建立與回收物件,嚴重影響到了效能。

原文連結