導航:首頁 > 編程語言 > java多線程map

java多線程map

發布時間:2024-08-08 09:06:58

java中幾種Map在什麼情況下使用,並簡單介紹原因及原理

一、Map用於保存具有映射關系的數據,Map里保存著兩組數據:key和value,它們都可以使任何引用類型的數據,但key不能重復。所以通過指定的key就可以取出對應的value。Map介面定義了如下常用的方法:
1、void clear():刪除Map中所以鍵值對。
2、boolean containsKey(Object key):查詢Map中是否包含指定key,如果包含則返回true。
3、boolean containsValue(Object value):查詢Map中是否包含指定value,如果包含則返回true。
4、Set entrySet():返回Map中所包含的鍵值對所組成的Set集合,每個集合元素都是Map.Entry對象(Entry是Map的內部類)。
5、Object get(Object key):返回指定key所對應的value,如Map中不包含key則返回null。
6、boolean isEmpty():查詢Map是否為空,如果空則返回true。
7、Set keySet():返回該Map中所有key所組成的set集合。
8、Object put(Object key,Object value):添加一個鍵值對,如果已有一個相同的key值則新的鍵值對覆蓋舊的鍵值對。
9、void putAll(Map m):將指定Map中的鍵值對復制到Map中。
10、Object remove(Object key):刪除指定key所對應的鍵值對,返回可以所關聯的value,如果key不存在,返回null。
11、int size():返回該Map里的鍵值對的個數。
12、Collection values():返回該Map里所有value組成的Collection。
Map中包含一個內部類:Entry。該類封裝了一個鍵值對,它包含了三個方法:
1、Object getKey():返回該Entry里包含的key值。
2、Object getValeu():返回該Entry里包含的value值。
3、Object setValue(V value):設置該Entry里包含的value值,並返回新設置的value值。

二、HashMap和Hashtable實現類:
1、HashMap與HashTable的區別:
1) 同步性:Hashtable是同步的,這個類中的一些方法保證了Hashtable中的對象是線程安全的。而HashMap則是非同步的,因此HashMap中的對象並不是線程安全的。因為同步的要求會影響執行的效率,所以如果你不需要線程安全的集合那麼使用HashMap是一個很好的選擇,這樣可以避免由於同步帶來的不必要的性能開銷,從而提高效率。
2) 值:HashMap可以讓你將空值作為一個表的條目的key或value,但是Hashtable是不能放入空值的。HashMap最多隻有一個key值為null,但可以有無數多個value值為null。
2、性能:HashMap的性能最好,HashTable的性能是最差(因為它是同步的)
3、注意:
1)用作key的對象必須實現hashCode和equals方法。
2)不能保證其中的鍵值對的順序
3)盡量不要使用可變對象作為它們的key值。

三、LinkedHashMap:
它的父類是HashMap,使用雙向鏈表來維護鍵值對的次序,迭代順序與鍵值對的插入順序保持一致。LinkedHashMap需要維護元素的插入順序,so性能略低於HashMap,但在迭代訪問元素時有很好的性能,因為它是以鏈表來維護內部順序。

四、TreeMap:
Map介面派生了一個SortMap子介面,SortMap的實現類為TreeMap。TreeMap也是基於紅黑樹對所有的key進行排序,有兩種排序方式:自然排序和定製排序。Treemap的key以TreeSet的形式存儲,對key的要求與TreeSet對元素的要求基本一致。
1、Map.Entry firstEntry():返回最小key所對應的鍵值對,如Map為空,則返回null。
2、Object firstKey():返回最小key,如果為空,則返回null。
3、Map.Entry lastEntry():返回最大key所對應的鍵值對,如Map為空,則返回null。
4、Object lastKey():返回最大key,如果為空,則返回null。
5、Map.Entry higherEntry(Object key):返回位於key後一位的鍵值對,如果為空,則返回null。
6、Map.Entry lowerEntry(Object key):返回位於key前一位的鍵值對,如果為空,則返回null。
7、Object lowerKey(Object key):返回位於key前一位key值,如果為空,則返回null。
8、NavigableMap subMap(Object fromKey,boolean fromlnclusive,Object toKey,boolean toInciusive):返回該Map的子Map,其key范圍從fromKey到toKey。
9、SortMap subMap(Object fromKey,Object toKey );返回該Map的子Map,其key范圍從fromkey(包括)到tokey(不包括)。
10、SortMap tailMap(Object fromkey ,boolean inclusive):返回該Map的子Map,其key范圍大於fromkey(是否包括取決於第二個參數)的所有key。
11、 SortMap headMap(Object tokey ,boolean inclusive):返回該Map的子Map,其key范圍小於tokey(是否包括取決於第二個參數)的所有key。

五、WeakHashMap:
WeakHashMap與HashMap的用法基本相同,區別在於:後者的key保留對象的強引用,即只要HashMap對象不被銷毀,其對象所有key所引用的對象不會被垃圾回收,HashMap也不會自動刪除這些key所對應的鍵值對對象。但WeakHashMap的key所引用的對象沒有被其他強引用變數所引用,則這些key所引用的對象可能被回收。WeakHashMap中的每個key對象保存了實際對象的弱引用,當回收了該key所對應的實際對象後,WeakHashMap會自動刪除該key所對應的鍵值對。

六、IdentityHashMap類:
IdentityHashMap與HashMap基本相似,只是當兩個key嚴格相等時,即key1==key2時,它才認為兩個key是相等的 。IdentityHashMap也允許使用null,但不保證鍵值對之間的順序。

七、EnumMap類:
1、EnumMap中所有key都必須是單個枚舉類的枚舉值,創建EnumMap時必須顯示或隱式指定它對應的枚舉類。
2、EnumMap根據key的自然順序,即枚舉值在枚舉類中定義的順序,來維護鍵值對的次序。
3、EnumMap不允許使用null作為key值,但value可以。

⑵ HashMap為什麼不安全

我們都知道HashMap是線程不安全的,在多線程環境中不建議使用,但是其線程不安全主要體現在什麼地方呢,本文將對該問題進行解密。

1.jdk1.7中的HashMap

在jdk1.8中對HashMap做了很多優化,這里先分析在jdk1.7中的問題,相信大家都知道在jdk1.7多線程環境下HashMap容易出現死循環,這里我們先用代碼來模擬出現死循環的情況:

publicclassHashMapTest{publicstaticvoidmain(String[]args){HashMapThreadthread0=newHashMapThread();HashMapThreadthread1=newHashMapThread();HashMapThreadthread2=newHashMapThread();HashMapThreadthread3=newHashMapThread();HashMapThreadthread4=newHashMapThread();thread0.start();thread1.start();thread2.start();thread3.start();thread4.start();}}{privatestaticAtomicIntegerai=newAtomicInteger();privatestaticMapmap=newHashMap<>();@Overridepublicvoidrun(){while(ai.get()<1000000){map.put(ai.get(),ai.get());ai.incrementAndGet();}}}

上述代碼比較簡單,就是開多個線程不斷進行put操作,並且HashMap與AtomicInteger都是全局共享的。

在多運行幾次該代碼後,出現如下死循環情形:

2.jdk1.8中HashMap

在jdk1.8中對HashMap進行了優化,在發生hash碰撞,不再採用頭插法方式,而是直接插入鏈表尾部,因此不會出現環形鏈表的情況,但是在多線程的情況下仍然不安全,這里我們看jdk1.8中HashMap的put操作源碼:

  • finalVputVal(inthash,Kkey,Vvalue,booleanonlyIfAbsent,booleanevict){Node[]tab;Nodep;intn,i;if((tab=table)==null||(n=tab.length)==0)n=(tab=resize()).length;if((p=tab[i=(n-1)&hash])==null)//如果沒有hash碰撞則直接插入元素tab[i]=newNode(hash,key,value,null);else{Nodee;Kk;if(p.hash==hash&&((k=p.key)==key||(key!=null&&key.equals(k))))e=p;elseif(pinstanceofTreeNode)e=((TreeNode)p).putTreeVal(this,tab,hash,key,value);else{for(intbinCount=0;;++binCount){if((e=p.next)==null){p.next=newNode(hash,key,value,null);if(binCount>=TREEIFY_THRESHOLD-1)//-1for1sttreeifyBin(tab,hash);break;}if(e.hash==hash&&((k=e.key)==key||(key!=null&&key.equals(k))))break;p=e;}}if(e!=null){//=e.value;if(!onlyIfAbsent||oldValue==null)e.value=value;afterNodeAccess(e);returnoldValue;}}++modCount;if(++size>threshold)resize();afterNodeInsertion(evict);returnnull;}

  • 這是jdk1.8中HashMap中put操作的主函數, 注意第6行代碼,如果沒有hash碰撞則會直接插入元素。

    如果線程A和線程B同時進行put操作,剛好這兩條不同的數據hash值一樣,並且該位置數據為null,所以這線程A、B都會進入第6行代碼中。

    假設一種情況,線程A進入後還未進行數據插入時掛起,而線程B正常執行,從而正常插入數據,然後線程A獲取CPU時間片,此時線程A不用再進行hash判斷了,問題出現:線程A會把線程B插入的數據給覆蓋,發生線程不安全。

    總結

    首先HashMap是線程不安全的,其主要體現:

  • 在jdk1.7中,在多線程環境下,擴容時會造成環形鏈或數據丟失。

  • 在jdk1.8中,在多線程環境下,會發生數據覆蓋的情況。

  • 閱讀全文

    與java多線程map相關的資料

    熱點內容
    要我蘋果賬號密碼忘記了怎麼辦 瀏覽:578
    快快卡在配置游戲文件 瀏覽:393
    數據包重發時間怎麼調整 瀏覽:882
    youtubeapp怎麼下載 瀏覽:366
    編程檢測是什麼 瀏覽:753
    網路攝像機的傳輸距離 瀏覽:941
    超值貓qq群購秒殺群 瀏覽:138
    pdf文件能備注嗎 瀏覽:174
    html可視化數據源碼在哪裡 瀏覽:387
    adobereader專用卸載工具 瀏覽:28
    vivo手機數據如何備份 瀏覽:888
    ithmb文件轉換器 瀏覽:66
    看病找什麼網站好 瀏覽:579
    linux如何查看文件系統 瀏覽:581
    linux統計點頻率 瀏覽:627
    全民泡泡大戰安琪兒升級 瀏覽:620
    編程scratch如何保存 瀏覽:750
    aspnetmvc傳json 瀏覽:132
    如何下載看神片的狐狸視頻app 瀏覽:579
    怎樣將木紋文件添加到cad 瀏覽:223

    友情鏈接