Java?HashTable與Collections.synchronizedMap源碼深入解析
一、類繼承關(guān)系圖
二、HashTable介紹
HashTable的操作幾乎和HashMap一致,主要的區(qū)別在于HashTable為了實(shí)現(xiàn)多線程安全,在幾乎所有的方法上都加上了synchronized鎖,而加鎖的結(jié)果就是HashTable操作的效率十分低下。
不建議使用HashTable,Oracle官方也將其廢棄,建議在多線程環(huán)境下使用ConcurrentHashMap類。
三、HashTable和HashMap的對(duì)比
1.線程安全
HashMap是線程不安全的類,多線程下會(huì)造成并發(fā)沖突,但單線程下運(yùn)行效率較高;HashTable是線程安全的類,很多方法都是用synchronized修飾,但同時(shí)因?yàn)榧渔i導(dǎo)致并發(fā)效率低下,單線程環(huán)境效率也十分低;
2.插入null
HashMap允許有鍵為null,值為null;但HashTable不允許鍵或值為null;
3.容量
HashMap底層數(shù)組長(zhǎng)度必須為2的冪,這樣做是為了hash準(zhǔn)備,默認(rèn)為16;而HashTable底層數(shù)組長(zhǎng)度可以為任意值,這就造成了hash算法散射不均勻,容易造成hash沖突,默認(rèn)為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ī)設(shè)計(jì),將底層table長(zhǎng)度設(shè)計(jì)為2的冪,使用位與運(yùn)算代替取模運(yùn)算,減少運(yùn)算消耗;而HashTable的hash算法首先使得hash值小于整型數(shù)最大值,再通過取模進(jìn)行散射運(yùn)算;
int hash = key.hashCode(); int index = (hash & 0x7FFFFFFF) % tab.length;
5.擴(kuò)容機(jī)制
HashMap創(chuàng)建一個(gè)為原先2倍的數(shù)組,然后對(duì)原數(shù)組進(jìn)行遍歷以及然后重新通過位運(yùn)算計(jì)算位置,不管是紅黑樹還是鏈表,都先采取尾插法分成兩條鏈,然后再通過鏈的數(shù)量決定是樹化還是轉(zhuǎn)鏈表(其實(shí)就是把TreeNode變成Node,因?yàn)榧t黑樹分成兩條鏈后其實(shí)就是TreeNode組成的鏈表);HashTable擴(kuò)容將創(chuàng)建一個(gè)原長(zhǎng)度2倍的數(shù)組 + 1,然后對(duì)原數(shù)組進(jìn)行遍歷以及rehash,頭插法;
hashTable的擴(kuò)容:
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.結(jié)構(gòu)區(qū)別
HashMap是由數(shù)組+鏈表形成,在JDK1.8之后鏈表長(zhǎng)度大于8時(shí)轉(zhuǎn)化為紅黑樹;而HashTable一直都是數(shù)組+鏈表;
四、Collections.synchronizedMap解析
1.Collections.synchronizedMap是怎么實(shí)現(xiàn)線程安全的
調(diào)用Collections.synchronizedMap實(shí)際是給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
再看構(gòu)造方法:
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; }
通過構(gòu)造方法,把map傳進(jìn)來,如果不傳Object mutex參數(shù),mutex就是this
再看一下具體是怎么實(shí)現(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直接鎖整個(gè)方法粒度差不多,都不推薦使用,推薦使用ConcurrentHashMap
到此這篇關(guān)于Java HashTable與Collections.synchronizedMap源碼深入解析的文章就介紹到這了,更多相關(guān)Java HashTable與Collections.synchronizedMap內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- Java同步鎖Synchronized底層源碼和原理剖析(推薦)
- java同步鎖的正確使用方法(必看篇)
- 95%的Java程序員人都用不好Synchronized詳解
- Java?synchronized同步關(guān)鍵字工作原理
- Java synchronized偏向鎖的概念與使用
- Java?synchronized輕量級(jí)鎖實(shí)現(xiàn)過程淺析
- Java synchronized重量級(jí)鎖實(shí)現(xiàn)過程淺析
- Java @Transactional與synchronized使用的問題
- Java?synchronized與死鎖深入探究
- Java synchronized與CAS使用方式詳解
- 淺析Java關(guān)鍵詞synchronized的使用
- synchronized及JUC顯式locks?使用原理解析
- java鎖synchronized面試常問總結(jié)
- Java?Synchronized鎖的使用詳解
- AQS加鎖機(jī)制Synchronized相似點(diǎn)詳解
- Java必會(huì)的Synchronized底層原理剖析
- 一個(gè)例子帶你看懂Java中synchronized關(guān)鍵字到底怎么用
- 詳解Java?Synchronized的實(shí)現(xiàn)原理
- Synchronized?和?ReentrantLock?的實(shí)現(xiàn)原理及區(qū)別
- Java同步鎖synchronized用法的最全總結(jié)
相關(guān)文章
IntelliJ IDEA 2021.1 EAP 1 發(fā)布支持 Java 16 和 WSL 2
這篇文章主要介紹了IntelliJ IDEA 2021.1 EAP 1 發(fā)布支持 Java 16 和 WSL 2,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-02-02SpringBoot學(xué)習(xí)篇之@Valid與@Validated的區(qū)別
@Valid是使用Hibernate?validation的時(shí)候使用,@Validated是只用Spring?Validator校驗(yàn)機(jī)制使用,下面這篇文章主要給大家介紹了關(guān)于SpringBoot學(xué)習(xí)篇之@Valid與@Validated區(qū)別的相關(guān)資料,需要的朋友可以參考下2022-11-11java 裝飾模式(Decorator Pattern)詳解
這篇文章主要介紹了java 裝飾模式(Decorator Pattern)詳解的相關(guān)資料,需要的朋友可以參考下2016-10-10詳解spring boot 以jar的方式啟動(dòng)常用shell腳本
本篇文章主要介紹了詳解spring boot 以jar的方式啟動(dòng)常用shell腳本,具有一定的參考價(jià)值,有興趣的可以了解一下2017-09-09淺談MyBatis3 DynamicSql風(fēng)格語法使用指南
這篇文章主要介紹了淺談MyBatis3 DynamicSql風(fēng)格語法使用指南,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-03-03Java實(shí)現(xiàn)圖章或簽名插在pdf的固定位置
使用Java技術(shù)在word轉(zhuǎn)換成pdf過程中實(shí)現(xiàn)將圖章或者簽名插入在pdf中,并生成帶圖章或者簽名的pdf,來完成某些特定場(chǎng)景的需求,文中有詳細(xì)的代碼示例,需要的朋友可以參考下2023-10-10