HashMap vs ConcurrentHashMap — 示例及Iterator探秘
2019獨角獸企業重金招聘Python工程師標準>>>
如果你是一名Java開發人員,我能夠確定你肯定知道ConcurrentModificationException,它是在使用迭代器遍歷集合對象時修改集合對象造成的(并發修改)異常。實際上,Java的集合框架是迭代器設計模式的一個很好的實現。
Java 1.5引入了java.util.concurrent包,其中Collection類的實現允許在運行過程中修改集合對象。
ConcurrentHashMap是一個與HashMap很相似的類,但是它支持在運行時修改集合對象。
讓我們通過一個簡單的程序來幫助理解:
ConcurrentHashMapExample.java
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | packagecom.journaldev.util; importjava.util.HashMap; importjava.util.Iterator; importjava.util.Map; importjava.util.concurrent.ConcurrentHashMap; publicclassConcurrentHashMapExample { publicstaticvoidmain(String[] args) { //ConcurrentHashMap Map<String,String> myMap =newConcurrentHashMap<String,String>(); myMap.put("1","1"); myMap.put("2","1"); myMap.put("3","1"); myMap.put("4","1"); myMap.put("5","1"); myMap.put("6","1"); System.out.println("ConcurrentHashMap before iterator: "+myMap); Iterator<String> it = myMap.keySet().iterator(); while(it.hasNext()){ String key = it.next(); if(key.equals("3")) myMap.put(key+"new","new3"); } System.out.println("ConcurrentHashMap after iterator: "+myMap); //HashMap myMap =newHashMap<String,String>(); myMap.put("1","1"); myMap.put("2","1"); myMap.put("3","1"); myMap.put("4","1"); myMap.put("5","1"); myMap.put("6","1"); System.out.println("HashMap before iterator: "+myMap); Iterator<String> it1 = myMap.keySet().iterator(); while(it1.hasNext()){ String key = it1.next(); if(key.equals("3")) myMap.put(key+"new","new3"); } System.out.println("HashMap after iterator: "+myMap); } } |
當我們試著運行上面的程序,輸出如下:
| 1 2 3 4 5 6 7 | ConcurrentHashMap before iterator: {1=1, 5=1, 6=1, 3=1, 4=1, 2=1} ConcurrentHashMap after iterator: {1=1, 3new=new3, 5=1, 6=1, 3=1, 4=1, 2=1} HashMap before iterator: {3=1, 2=1, 1=1, 6=1, 5=1, 4=1} Exceptioninthread"main"java.util.ConcurrentModificationException at java.util.HashMap$HashIterator.nextEntry(HashMap.java:793) at java.util.HashMap$KeyIterator.next(HashMap.java:828) at com.test.ConcurrentHashMapExample.main(ConcurrentHashMapExample.java:44) |
查看輸出,很明顯ConcurrentHashMap可以支持向map中添加新元素,而HashMap則拋出了ConcurrentModificationException。
查看異常堆棧記錄,可以發現是下面這條語句拋出異常:
| 1 | String key = it1.next(); |
這就意味著新的元素在HashMap中已經插入了,但是在迭代器執行時出現錯誤。事實上,集合對象的迭代器提供快速失敗(Fail-Fast)的機制,即修改集合對象結構或者元素數量都會使迭代器觸發這個異常。
但是迭代器是怎么知道HashMap被修改了呢,我們可以一次取出HashMap的所有Key然后進行遍歷。
HashMap包含一個修改計數器,當你調用它的next()方法來獲取下一個元素時,迭代器將會用到這個計數器。
HashMap.java
| 1 2 3 4 5 6 7 | /** * HashMap結構的修改次數 * 結構修改是指:改變了HashMap中mapping的個數或者其中的內部結構(比如,重新計算hash值) * 這個字段在通過Collection操作Hashmap時提供快速失敗(Fail-fast)功能。 * (參見 ConcurrentModificationException)。 */ transientvolatileintmodCount; |
現在為了證明上面的觀點,我們對原來的代碼做一點修改,使迭代器在插入新的元素后跳出循環。只要在調用put方法后增加一個break:
| 1 2 3 4 | if(key.equals("3")){ myMap.put(key+"new","new3"); break; } |
再執行修改后的代碼,會得到下面的輸出結果:
| 1 2 3 4 | ConcurrentHashMap before iterator: {1=1, 5=1, 6=1, 3=1, 4=1, 2=1} ConcurrentHashMap after iterator: {1=1, 3new=new3, 5=1, 6=1, 3=1, 4=1, 2=1} HashMap before iterator: {3=1, 2=1, 1=1, 6=1, 5=1, 4=1} HashMap after iterator: {3=1, 2=1, 1=1, 3new=new3, 6=1, 5=1, 4=1} |
最后,如果我們不添加新的元素而是修改已經存在的鍵值對會不會拋出異常呢?
修改原來的程序并且自己驗證一下:
| 1 2 | //myMap.put(key+"new", "new3"); myMap.put(key,"new3"); |
如果你對于輸出結果感覺困惑或者震驚,在下面評論。我會很樂意給出進一步解釋。
你有沒有注意到那些我們在創建集合和迭代器時的尖括號,在Java中這叫做泛型,當涉及到編譯時的類型檢查和去除運行時的ClassCastException的時候會很有幫助。點擊這里可以了解更多泛型教程。
原文鏈接:? journaldev ?翻譯:? ImportNew.com? -? 風戀星譯文鏈接:? http://www.importnew.com/8162.html
[? 轉載請保留原文出處、譯者和譯文鏈接。 ]
轉載于:https://my.oschina.net/u/165124/blog/373724
總結
以上是生活随笔為你收集整理的HashMap vs ConcurrentHashMap — 示例及Iterator探秘的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 汇编题目:编写包含多个功能子程序的中断例
- 下一篇: 快速开发系统之前台页面 ---- NO1