ConcurrentHashMap Collections.synchronizedMap和Hashtable討論

來源:互聯網
上載者:User

標籤:ar   io   使用   java   on   資料   問題   bs   cti   

在Java類庫中出現的第一個關聯的集合類是Hashtable,它是JDK1.0的一部分。 Hashtable提供了一種便於使用的、安全執行緒的、關聯的map功能,這當然也是方便的。然而,執行緒安全性是憑代價換來的――Hashtable的所有方法都是同步的。此時,無競爭的同步會導致可觀的效能代價。Hashtable的後繼者HashMap是作為JDK1.2中的集合架構的一部分出現的,它通過提供一個不同步的基類和一個同步的封裝器Collections.synchronizedMap,解決了執行緒安全性問題。
通過將基本的功能從執行緒安全性中分離開來,Collections.synchronizedMap允許需要同步的使用者可以擁有同步,而不需要同步的使用者則不必為同步付出代價。Hashtable和synchronizedMap所採取的獲得同步的簡單方法(同步Hashtable中或者同步的Map封裝器對象中的每個方法)有兩個主要的不足。首先,這種方法對於延展性是一種障礙,因為一次只能有一個線程可以訪問hash表。同時,這樣仍不足以提供真正的執行緒安全性,許多公用的混合操作仍然需要額外的同步。
雖然諸如get()和put()之類的簡單操作可以在不需要額外同步的情況下安全地完成,但還是有一些公用的操作序列,例如迭代或者put-if-absent(空則放入),需要外部的同步,以避免資料爭用。有條件的執行緒安全性同步的集合封裝器 synchronizedMap和synchronizedList,有時也被稱作有條件地安全執行緒――所有單個的操作都是安全執行緒的,但是多個操作組成的操作序列卻可能導致資料爭用,因為在操作序列中控制流程取決於前面操作的結果。
如果一個條目不在Map中,那麼添加這個條目。不幸的是,在 containsKey()方法返回到put()方法被調用這段時間內,可能會有另一個線程也插入一個帶有相同鍵的值。如果您想確保只有一次插入,您需要用一個對Map進行同步的同步塊將這一對語句封裝起來。List.size()的結果在迴圈的執行期間可能會變得無效,因為另一個線程可以從這個列表中刪除條目。可能在進入迴圈的最後一次迭代之後有一個條目被另一個線程刪除了,則List.get()將返回null,拋出一個 NullPointerException異常。那麼,採取什麼措施才能避免這種情況呢?如果當您正在迭代一個List時另一個線程也可能正在訪問這個 List,那麼在進行迭代時您必須使用一個synchronized塊將這個List封裝起來,在List上同步,從而鎖住整個List。
這樣做雖然解決了資料爭用問題,但是在並發性方面付出了更多的代價,因為在迭代期間鎖住整個List會阻塞其他線程,使它們在很長一段時間內不能訪問這個列表。集合架構引入了迭代器,用於遍曆一個列表或者其他集合,從而最佳化了對一個集合中的元素進行迭代的過程。然而,在java.util集合類中實現的迭代器極易崩潰,也就是說,如果在一個線程正在通過一個Iterator遍曆集合時,另一個線程也來修改這個集合,那麼接下來的 Iterator.hasNext()或Iterator.next()調用,會拋出ConcurrentModificationException異常。
如果想要防止出現ConcurrentModificationException異常,那麼當您進行中迭代時,您必須使用一個在 Listl上同步的synchronized塊將該List封裝起來,從而鎖住整個List。(也可以調用List.toArray(),在不同步的情況下對數組進行迭代,但是如果列表比較大的話這樣做代價很高)。

而ConcurrentHashMap是DougLea的util.concurrent包的一部分,現已被整合到 JDK5.0中,它提供比Hashtable或者synchronizedMap更高程度的並發性。而且,對於大多數成功的get()操作它會設法避免完全鎖定,其結果就是使得並發應用程式有著非常好的輸送量。
1 針對輸送量進行最佳化
ConcurrentHashMap使用了幾個技巧來獲得高程度的並發以及避免鎖定,包括為不同的hashbucket(桶)使用多個寫鎖和使用JMM的不確定性來最小化鎖被保持的時間——或者根本避免擷取鎖。對於大多數一般用法來說它是經過最佳化的,這些用法往往會檢索一個很可能在map中已經存在的值。事實上,多數成功的get()操作根本不需要任何鎖定就能運行。(警告:不要自己試圖這樣做!想比JMM聰明不像看上去的那麼容易。util.concurrent類是由並發專家編寫的,並且在JMM安全性方面經過了嚴格的同行評審。)
2 多個寫鎖
我們可以回想一下,Hashtable(或者替代方案 Collections.synchronizedMap)的延展性的主要障礙是它使用了一個map範圍(map-wide)的鎖,為了保證插入、刪除或者檢索操作的完整性必須保持這樣一個鎖,而且有時候甚至還要為了保證迭代遍曆操作的完整性保持這樣一個鎖。這樣一來,只要鎖被保持,就從根本上阻止了其他線程訪問Map,即使處理器有空閑也不能訪問,這樣大大地限制了並發性。
ConcurrentHashMap摒棄了單一的map範圍的鎖,取而代之的是由32個鎖組成的集合,其中每個鎖負責保護hashbucket的一個子集。鎖主要由變化性操作(put()和remove())使用。具有32 個獨立的鎖意味著最多可以有32個線程可以同時修改map。這並不一定是說在並發地對map進行寫操作的線程數少於32時,另外的寫操作不會被阻塞—— 32對於寫線程來說是理論上的並發限制數目,但是實際上可能達不到這個值。但是,32依然比1要好得多,而且對於運行於目前這一代的電腦系統上的大多數應用程式來說已經足夠了。
3 map範圍的操作
有32個獨立的鎖,其中每個鎖保護hashbucket的一個子集,這樣需要獨佔訪問 map的操作就必須獲得所有32個鎖。一些map範圍的操作,比如說size()和isEmpty(),也許能夠不用一次鎖整個map(通過適當地限定這些操作的語義),但是有些操作,比如map重排(擴大hashbucket的數量,隨著map的增長重新分配元素),則必須保證獨佔訪問。Java語言不提供用於擷取可變大小的鎖集合的簡便方法。必須這麼做的情況很少見,一旦碰到這種情況,可以用遞迴方法來實現。
4 JMM概述
在進入 put()、get()和remove()的實現之前,讓我們先簡單地看一下JMM。JMM掌管著一個線程對記憶體的動作(讀和寫)影響其他線程對記憶體的動作的方式。由於使用處理器寄存器和預先處理cache來提高記憶體訪問速度帶來的效能提升,Java語言規範(JLS)允許一些記憶體操作並不對於所有其他線程立即可見。有兩種語言機制可用於保證跨線程記憶體操作的一致性——synchronized和volatile。
按照JLS的說法,“在沒有顯式同步的情況下,一個實現可以自由地更新主存,更新時所採取的順序可能是出人意料的。”其意思是說,如果沒有同步的話,在一個給定線程中某種順序的寫操作對於另外一個不同的線程來說可能呈現出不同的順序,並且對記憶體變數的更新從一個線程傳播到另外一個線程的時間是不可預測的。
雖然使用同步最常見的原因是保證對代碼關鍵區段的原子訪問,但實際上同步提供三個獨立的功能——原子性、可見度和順序性。原子性非常簡單——同步實施一個可重新進入的(reentrant)互斥,防止多於一個的線程同時執行由一個給定的監視器保護的代碼塊。不幸的是,多數文章都只關注原子性方面,而忽略了其他方面。但是同步在JMM中也扮演著很重要的角色,會引起JVM在獲得和釋放監視器的時候執行記憶體壁壘(memorybarrier)。
一個線程在獲得一個監視器之後,它執行一個讀屏障(readbarrier)——使得緩衝線上程局部記憶體(比如說處理器緩衝或者處理器寄存器)中的所有變數都失效,這樣就會導致處理器重新從主存中讀取同步代碼塊使用的變數。與此類似,在釋放監視器時,線程會執行一個寫屏障(writebarrier)——將所有修改過的變數寫回主存。互斥獨佔和記憶體壁壘結合使用意味著只要您在程式設計的時候遵循正確的同步法則(也就是說,每當寫一個後面可能被其他線程訪問的變數,或者讀取一個可能最後被另一個線程修改的變數時,都要使用同步),每個線程都會得到它所使用的共用變數的正確的值。

ConcurrentHashMap Collections.synchronizedMap和Hashtable討論

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.