JAVA中的執行緒安全與非執行緒安全理解
阿新 • • 發佈:2019-01-31
執行緒安全性不是一個非真即假的命題。 Vector 的方法都是同步的,並且 Vector 明確地設計為在多執行緒環境中工作。但是它的執行緒安全性是有限制的,即在某些方法之間有狀態依賴(類似地,如果在迭代過程中
Vector 被其他執行緒修改,那麼由 Vector.iterator() 返回的 iterator會丟擲ConcurrentModifiicationException)。
對於 Java 類中常見的執行緒安全性級別,沒有一種分類系統可被廣泛接受,不過重要的是在編寫類時儘量記錄下它們的執行緒安全行為。
Bloch 給出了描述五類執行緒安全性的分類方法:不可變、執行緒安全、有條件執行緒安全、執行緒相容和執行緒對立。只要明確地記錄下執行緒安全特性,那麼您是否使用這種系統都沒關係。這種系統有其侷限性 – 各類之間的界線不是百分之百地明確,而且有些情況它沒照顧到 – 但是這套系統是一個很好的起點。這種 分類系統的核心是呼叫者是否可以或者必須用外部同步包圍操作(或者一系列操作)。下面幾節分別描述了執行緒安全性的這五種類別。
執行緒安全性保證是很嚴格的 – 許多類,如 Hashtable 或者
Vector 都不能滿足這種嚴格的定義。
有條件的執行緒安全類對於單獨的操作可以是執行緒安全的,但是某些操作序列可能需要外部同步。條件執行緒安全的最常見的例子是遍歷由 Hashtable 或者 Vector 或者返回的迭代器 – 由這些類返回的 fail-fast 迭代器假定在迭代器進行遍歷的時候底層集合不會有變化。為了保證其他執行緒不會在遍歷的時候改變集合,進行迭代的執行緒應該確保它是獨佔性地訪問集合以實現遍歷的完整性。通常,獨佔性的訪問是由對鎖的同步保證的
– 並且類的文件應該說明是哪個鎖(通常是物件的內部 監視器(intrinsic monitor))。
如果對一個有條件執行緒安全類進行記錄,那麼您應該不僅要記錄它是有條件執行緒安全的,而且還要記錄必須防止哪些操作序列的併發訪問。使用者可以合理地假設其他操作序列不需要任何額外的同步。
執行緒相容
執行緒相容類不是執行緒安全的,但是可以通過正確使用同步而在併發環境中安全地使用。這可能意味著用一個 synchronized 塊包圍每一個方法呼叫,或者建立一個包裝器物件,其中每一個方法都是同步的(就像 Collections.synchronizedList() 一樣)。也可能意味著用 synchronized 塊包圍某些操作序列。為了最大程度地利用執行緒相容類,如果所有呼叫都使用同一個塊,那麼就不應該要求呼叫者對該塊同步。這樣做會使執行緒相容的物件作為變數例項包含在其他執行緒安全的物件中,從而可以利用其所有者物件的同步。
許多常見的類是執行緒相容的,如集合類 ArrayList 和 HashMap 、 java.text.SimpleDateFormat 、或者 JDBC 類 Connection 和 ResultSet 。