執行緒安全容器
阿新 • • 發佈:2019-01-31
1.同步容器類
同步容器類包括Vector和Hashtable,或者通過Collections.synchronizedXxx等工長方法建立的。
這些實現執行緒安全的方式:將他們的狀態封裝起來,並對每個共有方法加鎖。
1.1 同步容器類的問題
複合操作:迭代(反覆訪問元素,直到遍歷完容器中所有元素)、條件運算(若沒有則新增)。在其他執行緒併發地修改容器時,它們可能會變現出意料之外的行為。
如:
public static Object getLast(Vector list) {
int lastIndex = list.size() - 1;
return list.get(lastIndex);
}
public static void deleteLast(Vector list) {
int lastIndex = list.size() - 1;
list.remove(lastIndex);
}
當兩個執行緒同時分別執行上面的兩個方法時。會出現問題。如執行緒A呼叫getLast(), 執行緒B呼叫deleteLast(); 呼叫交替執行的圖如下:
結構是:getLast將丟擲ArrayIndexOutOfBoundsException異常。
1.2 客戶端加鎖實現同步容器問題
我們解決的思路是通過加鎖來保證Vector的大小在呼叫size和get之間不會發生變化。
如:
public static Object getLast(Vector list) {
synchronized(list) {
int lastIndex = list.size() - 1;
return list.get(lastIndex);
}
}
public static void deleteLast(Vector list) {
synchronized(list) {
int lastIndex = list.size() - 1;
list.remove(lastIndex);
}
}
1.3 迭代器與ConcurrentModificationException
同步容器類的迭代器在迭代時,如果被修改時,會變現出“及時失敗”的異常,即ConcurrentModificationException異常。
除了顯示的呼叫迭代會變現出“及時失敗” 的異常外。隱式的呼叫以下方法也有可能出現“及時失敗”,如:hashCode 、equals、containsAll、removeAll和retainAll等方法。
這種“及時失敗”的迭代器並不是一種完備的處理機制,而只是“善意地” 捕獲併發錯誤,因此只能作為併發問題的預警指示器。
解決辦法:
- 對容器加鎖
- 克隆容器
2. 併發容器
併發容器是從Java 5.0 後引入的。主要的目的是:通過併發容器來代替同步容器,可以極大地提高伸縮性並降低風險。