Java?HashTable與Collections.synchronizedMap源碼深入解析
一、類繼承關系圖
二、HashTable介紹
HashTable的操作幾乎和HashMap一致,主要的區(qū)別在于HashTable為了實現(xiàn)多線程安全,在幾乎所有的方法上都加上了synchronized鎖,而加鎖的結果就是HashTable操作的效率十分低下。
不建議使用HashTable,Oracle官方也將其廢棄,建議在多線程環(huán)境下使用ConcurrentHashMap類。
三、HashTable和HashMap的對比
1.線程安全
HashMap是線程不安全的類,多線程下會造成并發(fā)沖突,但單線程下運行效率較高;HashTable是線程安全的類,很多方法都是用synchronized修飾,但同時因為加鎖導致并發(fā)效率低下,單線程環(huán)境效率也十分低;
2.插入null
HashMap允許有鍵為null,值為null;但HashTable不允許鍵或值為null;
3.容量
HashMap底層數(shù)組長度必須為2的冪,這樣做是為了hash準備,默認為16;而HashTable底層數(shù)組長度可以為任意值,這就造成了hash算法散射不均勻,容易造成hash沖突,默認為11;
public Hashtable(int initialCapacity, float loadFactor) { if (initialCapacity < 0) throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity); if (loadFactor <= 0 || Float.isNaN(loadFactor)) throw new IllegalArgumentException("Illegal Load: "+loadFactor); if (initialCapacity==0) initialCapacity = 1; this.loadFactor = loadFactor; table = new Entry<?,?>[initialCapacity]; threshold = (int)Math.min(initialCapacity * loadFactor, MAX_ARRAY_SIZE + 1); } /** * Constructs a new, empty hashtable with the specified initial capacity * and default load factor (0.75). * * @param initialCapacity the initial capacity of the hashtable. * @exception IllegalArgumentException if the initial capacity is less * than zero. */ public Hashtable(int initialCapacity) { this(initialCapacity, 0.75f); } /** * Constructs a new, empty hashtable with a default initial capacity (11) * and load factor (0.75). */ public Hashtable() { this(11, 0.75f); } /** * Constructs a new hashtable with the same mappings as the given * Map. The hashtable is created with an initial capacity sufficient to * hold the mappings in the given Map and a default load factor (0.75). * * @param t the map whose mappings are to be placed in this map. * @throws NullPointerException if the specified map is null. * @since 1.2 */ public Hashtable(Map<? extends K, ? extends V> t) { this(Math.max(2*t.size(), 11), 0.75f); putAll(t); }
4.Hash映射
HashMap的hash算法通過非常規(guī)設計,將底層table長度設計為2的冪,使用位與運算代替取模運算,減少運算消耗;而HashTable的hash算法首先使得hash值小于整型數(shù)最大值,再通過取模進行散射運算;
int hash = key.hashCode(); int index = (hash & 0x7FFFFFFF) % tab.length;
5.擴容機制
HashMap創(chuàng)建一個為原先2倍的數(shù)組,然后對原數(shù)組進行遍歷以及然后重新通過位運算計算位置,不管是紅黑樹還是鏈表,都先采取尾插法分成兩條鏈,然后再通過鏈的數(shù)量決定是樹化還是轉鏈表(其實就是把TreeNode變成Node,因為紅黑樹分成兩條鏈后其實就是TreeNode組成的鏈表);HashTable擴容將創(chuàng)建一個原長度2倍的數(shù)組 + 1,然后對原數(shù)組進行遍歷以及rehash,頭插法;
hashTable的擴容:
int newCapacity = (oldCapacity << 1) + 1;
hashTable的頭插法:
for (int i = oldCapacity ; i-- > 0 ;) { for (Entry<K,V> old = (Entry<K,V>)oldMap[i] ; old != null ; ) { Entry<K,V> e = old; old = old.next; int index = (e.hash & 0x7FFFFFFF) % newCapacity; e.next = (Entry<K,V>)newMap[index]; newMap[index] = e; } }
6.結構區(qū)別
HashMap是由數(shù)組+鏈表形成,在JDK1.8之后鏈表長度大于8時轉化為紅黑樹;而HashTable一直都是數(shù)組+鏈表;
四、Collections.synchronizedMap解析
1.Collections.synchronizedMap是怎么實現(xiàn)線程安全的
調用Collections.synchronizedMap實際是給Map包裝成了SynchronizedMap
public static <K,V> Map<K,V> synchronizedMap(Map<K,V> m) { return new SynchronizedMap<>(m); }
2.SynchronizedMap源碼
先看屬性:
private final Map<K,V> m; // Backing Map final Object mutex; // Object on which to synchronize
再看構造方法:
SynchronizedMap(Map<K,V> m) { this.m = Objects.requireNonNull(m); mutex = this; } SynchronizedMap(Map<K,V> m, Object mutex) { this.m = m; this.mutex = mutex; }
通過構造方法,把map傳進來,如果不傳Object mutex參數(shù),mutex就是this
再看一下具體是怎么實現(xiàn)線程安全的:
public int size() { synchronized (mutex) {return m.size();} } public boolean isEmpty() { synchronized (mutex) {return m.isEmpty();} } public boolean containsKey(Object key) { synchronized (mutex) {return m.containsKey(key);} } public boolean containsValue(Object value) { synchronized (mutex) {return m.containsValue(value);} } public V get(Object key) { synchronized (mutex) {return m.get(key);} } public V put(K key, V value) { synchronized (mutex) {return m.put(key, value);} } public V remove(Object key) { synchronized (mutex) {return m.remove(key);} } public void putAll(Map<? extends K, ? extends V> map) { synchronized (mutex) {m.putAll(map);} } public void clear() { synchronized (mutex) {m.clear();} }
發(fā)現(xiàn)幾乎所有操作Map的代碼,都把mutex作為鎖,獲取到鎖之后去操作Map。
這種和HashTable直接鎖整個方法粒度差不多,都不推薦使用,推薦使用ConcurrentHashMap
到此這篇關于Java HashTable與Collections.synchronizedMap源碼深入解析的文章就介紹到這了,更多相關Java HashTable與Collections.synchronizedMap內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
- Java同步鎖Synchronized底層源碼和原理剖析(推薦)
- java同步鎖的正確使用方法(必看篇)
- 95%的Java程序員人都用不好Synchronized詳解
- Java?synchronized同步關鍵字工作原理
- Java synchronized偏向鎖的概念與使用
- Java?synchronized輕量級鎖實現(xiàn)過程淺析
- Java synchronized重量級鎖實現(xiàn)過程淺析
- Java @Transactional與synchronized使用的問題
- Java?synchronized與死鎖深入探究
- Java synchronized與CAS使用方式詳解
- 淺析Java關鍵詞synchronized的使用
- synchronized及JUC顯式locks?使用原理解析
- java鎖synchronized面試常問總結
- Java?Synchronized鎖的使用詳解
- AQS加鎖機制Synchronized相似點詳解
- Java必會的Synchronized底層原理剖析
- 一個例子帶你看懂Java中synchronized關鍵字到底怎么用
- 詳解Java?Synchronized的實現(xiàn)原理
- Synchronized?和?ReentrantLock?的實現(xiàn)原理及區(qū)別
- Java同步鎖synchronized用法的最全總結
相關文章
IntelliJ IDEA 2021.1 EAP 1 發(fā)布支持 Java 16 和 WSL 2
這篇文章主要介紹了IntelliJ IDEA 2021.1 EAP 1 發(fā)布支持 Java 16 和 WSL 2,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2021-02-02SpringBoot學習篇之@Valid與@Validated的區(qū)別
@Valid是使用Hibernate?validation的時候使用,@Validated是只用Spring?Validator校驗機制使用,下面這篇文章主要給大家介紹了關于SpringBoot學習篇之@Valid與@Validated區(qū)別的相關資料,需要的朋友可以參考下2022-11-11java 裝飾模式(Decorator Pattern)詳解
這篇文章主要介紹了java 裝飾模式(Decorator Pattern)詳解的相關資料,需要的朋友可以參考下2016-10-10詳解spring boot 以jar的方式啟動常用shell腳本
本篇文章主要介紹了詳解spring boot 以jar的方式啟動常用shell腳本,具有一定的參考價值,有興趣的可以了解一下2017-09-09