日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

SynchronizedMap和ConcurrentHashMap的深入分析

發布時間:2025/7/14 编程问答 44 豆豆
生活随笔 收集整理的這篇文章主要介紹了 SynchronizedMap和ConcurrentHashMap的深入分析 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

轉自:http://blog.sina.com.cn/s/blog_5157093c0100hm3y.html

?

?

在開始之前,先介紹下Map是什么?

javadoc中對Map的解釋如下:

An object that?maps keys to values?. A map?cannot contain duplicate keys; each key can map to at most one value.

This interface takes the place of the Dictionary class, which was a totally abstract class rather than an interface.

The Map interface provides three collection views, which allow a map's contents to be viewed as a set of keys, collection of values, or set of key-value mappings.

?從上可知,Map用于存儲“key-value”元素對,它將一個key映射到一個而且只能是唯一的一個value。

Map可以使用多種實現方式,HashMap的實現采用的是hash表;而TreeMap采用的是紅黑樹。

?

1. Hashtable 和 HashMap

這兩個類主要有以下幾方面的不同:

??? Hashtable和HashMap都實現了Map接口,但是Hashtable的實現是基于Dictionary抽象類。

?

????在HashMap中,null可以作為鍵,這樣的鍵只有一個;可以有一個或多個鍵所對應的值為null。?當get()方法返回null值時,即可以表示 HashMap中沒有該鍵,也可以表示該鍵所對應的值為null。因此,在HashMap中不能由get()方法來判斷HashMap中是否存在某個鍵,而應該用containsKey()方法來判斷。而在Hashtable中,無論是key還是value都不能為null?。

?

?? 這兩個類最大的不同在于Hashtable是線程安全的,它的方法是同步了的,可以直接用在多線程環境中。而HashMap則不是線程安全的。在多線程環境中,需要手動實現同步機制。因此,在Collections類中提供了一個方法返回一個同步版本的HashMap用于多線程的環境:

?

Java代碼
  • public?static?<K,V>?Map<K,V>?synchronizedMap(Map<K,V>?m)?{ ??
  • ????return?new?SynchronizedMap<K,V>(m); ??
  • ?}??
  • 該方法返回的是一個SynchronizedMap?的實例。SynchronizedMap類是定義在Collections中的一個靜態內部類。它實現了Map接口,并對其中的每一個方法實現,通過synchronized?關鍵字進行了同步控制。

    ?

    2. 潛在的線程安全問題

    上面提到Collections為HashMap提供了一個并發版本SynchronizedMap。這個版本中的方法都進行了同步,但是這并不等于這個類就一定是線程安全的。在某些時候會出現一些意想不到的結果。

    如下面這段代碼:

    Java代碼
  • //?shm是SynchronizedMap的一個實例???
  • if(shm.containsKey('key')){ ??
  • ????????shm.remove(key); ??
  • }??
  • ?這段代碼用于從map中刪除一個元素之前判斷是否存在這個元素。這里的containsKey和reomve方法都是同步的,但是整段代碼卻不是。考慮這么一個使用場景:線程A執行了containsKey方法返回true,準備執行remove操作;這時另一個線程B開始執行,同樣執行了containsKey方法返回true,并接著執行了remove操作;然后線程A接著執行remove操作時發現此時已經沒有這個元素了。要保證這段代碼按我們的意愿工作,一個辦法就是對這段代碼進行同步控制,但是這么做付出的代價太大。

    ?

    在進行迭代時這個問題更改明顯。Map集合共提供了三種方式來分別返回鍵、值、鍵值對的集合:

    Java代碼
  • Set<K>?keySet(); ??
  • ??
  • Collection<V>?values(); ??
  • ??
  • Set<Map.Entry<K,V>>?entrySet();??
  • ?在這三個方法的基礎上,我們一般通過如下方式訪問Map的元素:

    Java代碼
  • Iterator?keys?=?map.keySet().iterator(); ??
  • ??
  • while(keys.hasNext()){ ??
  • ????????map.get(keys.next()); ??
  • }??
  • ?

    在這里,有一個地方需要注意的是:得到的keySet和迭代器都是Map中元素的一個“視圖”,而不是“副本”?。問題也就出現在這里,當一個線程正在迭代Map中的元素時,另一個線程可能正在修改其中的元素。此時,在迭代元素時就可能會拋出?ConcurrentModificationException異常。為了解決這個問題通常有兩種方法,一是直接返回元素的副本,而不是視圖。這個可以通過

    集合類的?toArray()?方法實現,但是創建副本的方式效率比之前有所降低,特別是在元素很多的情況下;另一種方法就是在迭代的時候鎖住整個集合,這樣的話效率就更低了。


    3. 更好的選擇:ConcurrentHashMap

    java5中新增了ConcurrentMap接口和它的一個實現類ConcurrentHashMap。ConcurrentHashMap提供了和Hashtable以及SynchronizedMap中所不同的鎖機制。Hashtable中采用的鎖機制是一次鎖住整個hash表,從而同一時刻只能由一個線程對其進行操作;而ConcurrentHashMap中則是一次鎖住一個桶。ConcurrentHashMap默認將hash表分為16個桶,諸如get,put,remove等常用操作只鎖當前需要用到的桶。這樣,原來只能一個線程進入,現在卻能同時有16個寫線程執行,并發性能的提升是顯而易見的。

    ?

    上面說到的16個線程指的是寫線程,而讀操作大部分時候都不需要用到鎖。只有在size等操作時才需要鎖住整個hash表。

    ?

    在迭代方面,ConcurrentHashMap使用了一種不同的迭代方式。在這種迭代方式中,當iterator被創建后集合再發生改變就不再是拋出ConcurrentModificationException,取而代之的是在改變時new新的數據從而不影響原有的數據iterator完成后再將頭指針替換為新的數據?,這樣iterator線程可以使用原來老的數據,而寫線程也可以并發的完成改變。

    總結

    以上是生活随笔為你收集整理的SynchronizedMap和ConcurrentHashMap的深入分析的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。