Java并发编程(十三)同步容器类
同步容器類
Vector、HashTable,我用的很少;Vecotr的實現(xiàn)和ArrayList挺接近的,不同的是Vector中很多的方法都用synchronized進行了同步。在不強調(diào)線程安全地時候用ArrayList,在需要線程安全地時候用Vector。
實現(xiàn)線程安全的方法:把它們的狀態(tài)封裝起來,并對每個公有方法都進行同步,使得每次都只有一個線程能訪問容器的狀態(tài)。
同步容器類問題
在某些情況下需要額外的客戶端加鎖來保護復(fù)合操作:
執(zhí)行"先檢查再運行"的demo
1 public class VectorDemo { 2 // 獲取最后一個元素 3 public static Object getLast(Vector list) { 4 int lastIndex = list.size() - 1; 5 return list.get(lastIndex); 6 } 7 // 刪除最后一個元素 8 public static void deleteLast(Vector list) { 9 int lastIndex = list.size() - 1; 10 list.remove(lastIndex); 11 } 12 }在客戶端中給Vector加上鎖,獲得一個線程安全的版本:
1 public class VectorDemo { 2 // 獲取最后一個元素 3 public static Object getLast(Vector list) { 4 synchronized (list) { 5 int lastIndex = list.size() - 1; 6 return list.get(lastIndex); 7 } 8 } 9 // 刪除最后一個元素 10 public static void deleteLast(Vector list) { 11 synchronized (list) { 12 int lastIndex = list.size() - 1; 13 list.remove(lastIndex); 14 } 15 } 16 }支持客戶端加鎖,可以創(chuàng)建一些新的操作,只要知道應(yīng)該使用哪一個鎖,那么這些新的操作就與容器的其他操作一樣都是原子操作。在這個例子中g(shù)etLast和deleteLast與Vector中其他的方法都共享一把鎖,也就是Vector實例自己,同一時刻只能進入其中的一個synchronized代碼塊中。
在同步容器類中,這些復(fù)合操作在沒有客戶端加鎖的情況下仍然是線程安全的,在其他線程并發(fā)修改容器的時候,可能會有意料之外的行為。
兩個方法都是線程安全的,但是組合起來會導(dǎo)致異常。可以在客戶端加鎖來解決不可靠迭代的問題,但是要犧牲一些伸縮性。通過在迭代期間持有Vector的鎖可以防止其他線程在迭代期間修改Vector。
迭代器與ConcurrentModificationException
對容器進行迭代的標(biāo)準(zhǔn)方式都是用Iterator。在同步容器類中,進行迭代時并沒有考慮到并發(fā)修改,而是用的"及時失敗",終于搞懂了快速失效了。這意味著在迭代時容器被修改將會拋出一個ConcurrentModificationException異常。
這種及時失敗的迭代器并不是一種完備的處理機制,而只是善意地捕獲并發(fā)錯誤,因此只能作為并發(fā)問題的預(yù)警指示器。采用的方法是,將計數(shù)器的變化與容器關(guān)聯(lián)起來:如果在迭代期間計數(shù)器被修改,那么hasNext或next將拋出ConcurrentModification。然而這種檢查是在沒有同步的情況下進行的,因此可能會看到失效值,而迭代可能并沒有意識到已經(jīng)發(fā)生了修改。
為什么不希望在迭代的時候加鎖:
隱藏迭代器
加鎖可以防止迭代器拋出ConcurrentModificationException,但是要記住在所有對共享容器進行迭代的地方都需要加鎖。
如果狀態(tài)與保護它的同步代碼之間相隔越遠,那么開發(fā)人員就越容易忘記在訪問狀態(tài)的時候使用正確的同步。正如封裝對象的狀態(tài)有助于維持不變性的條件一樣,封裝對象的同步機制同樣有助于確保實施同步策略。
容器的hashCode和equals方法同樣會間接地執(zhí)行迭代操作,當(dāng)容器所謂另一個容器的元素或者鍵值時就會出現(xiàn)這種情況。
轉(zhuǎn)載于:https://www.cnblogs.com/tuhooo/p/8073718.html
總結(jié)
以上是生活随笔為你收集整理的Java并发编程(十三)同步容器类的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Centos配置nginx反向代理808
- 下一篇: iOS 多线程的简单理解(3)执行方式