1. 程式人生 > >JAVA中的執行緒安全與非執行緒安全理解

JAVA中的執行緒安全與非執行緒安全理解

執行緒安全性不是一個非真即假的命題。 Vector 的方法都是同步的,並且 Vector 明確地設計為在多執行緒環境中工作。但是它的執行緒安全性是有限制的,即在某些方法之間有狀態依賴(類似地,如果在迭代過程中 Vector 被其他執行緒修改,那麼由 Vector.iterator() 返回的 iterator會丟擲ConcurrentModifiicationException)。 對於 Java 類中常見的執行緒安全性級別,沒有一種分類系統可被廣泛接受,不過重要的是在編寫類時儘量記錄下它們的執行緒安全行為。 Bloch 給出了描述五類執行緒安全性的分類方法:不可變、執行緒安全、有條件執行緒安全、執行緒相容和執行緒對立。只要明確地記錄下執行緒安全特性,那麼您是否使用這種系統都沒關係。這種系統有其侷限性 – 各類之間的界線不是百分之百地明確,而且有些情況它沒照顧到 – 但是這套系統是一個很好的起點。這種
分類系統
的核心是呼叫者是否可以或者必須用外部同步包圍操作(或者一系列操作)。下面幾節分別描述了執行緒安全性的這五種類別。

不可變

不可變的物件一定是執行緒安全的,並且永遠也不需要額外的同步[1]。因為一個不可變的物件只要構建正確,其外部可見狀態永遠也不會改變,永遠也不會看到它處於不一致的狀態。Java 類庫中大多數基本數值類如 Integer 、 String 和 BigInteger 都是不可變的。 需要注意的是,對於Integer,該類不提供add方法,加法是使用+來直接操作。而+操作是不具執行緒安全的。這是提供原子操作類AtomicInteger的原。 執行緒安全 執行緒安全的物件具有在上面“執行緒安全”一節中描述的屬性 – 由類的規格說明所規定的約束在物件被多個執行緒訪問時仍然有效,不管執行時環境如何排執行緒都不需要任何額外的同步。這種
執行緒安全性
保證是很嚴格的 – 許多類,如 Hashtable 或者 Vector 都不能滿足這種嚴格的定義。


有條件的

有條件的執行緒安全類對於單獨的操作可以是執行緒安全的,但是某些操作序列可能需要外部同步。條件執行緒安全的最常見的例子是遍歷由 Hashtable 或者 Vector 或者返回的迭代器 – 由這些類返回的 fail-fast 迭代器假定在迭代器進行遍歷的時候底層集合不會有變化。為了保證其他執行緒不會在遍歷的時候改變集合,進行迭代的執行緒應該確保它是獨佔性地訪問集合以實現遍歷的完整性。通常,獨佔性的訪問是由對鎖的同步保證的 – 並且類的文件應該說明是哪個鎖(通常是物件的內部
監視器
(intrinsic monitor))。 如果對一個有條件執行緒安全類進行記錄,那麼您應該不僅要記錄它是有條件執行緒安全的,而且還要記錄必須防止哪些操作序列的併發訪問。使用者可以合理地假設其他操作序列不需要任何額外的同步。 執行緒相容 執行緒相容類不是執行緒安全的,但是可以通過正確使用同步而在併發環境中安全地使用。這可能意味著用一個 synchronized 塊包圍每一個方法呼叫,或者建立一個包裝器物件,其中每一個方法都是同步的(就像 Collections.synchronizedList() 一樣)。也可能意味著用 synchronized 塊包圍某些操作序列。為了最大程度地利用執行緒相容類,如果所有呼叫都使用同一個塊,那麼就不應該要求呼叫者對該塊同步。這樣做會使執行緒相容的物件作為變數例項包含在其他執行緒安全的物件中,從而可以利用其所有者物件的同步。 許多常見的類是執行緒相容的,如集合類 ArrayList 和 HashMap 、 java.text.SimpleDateFormat 、或者 JDBC 類 Connection 和 ResultSet 。

執行緒對立

執行緒對立類是那些不管是否呼叫了外部同步都不能在併發使用時安全地呈現的類。執行緒對立很少見,當類修改靜態資料,而靜態資料會影響在其他執行緒中執行的其他類的行為,這時通常會出現執行緒對立。執行緒對立類的一個例子是呼叫 System.setOut() 的類。 原文地址: