原來看過1.7的hashmap底層,1.8更新後也稍微看了一下,沒有進行仔細的總結,今天總結一下1.8底層的原理。本文只討論1.8的底層原理。以下全文為1.8版本的
對於hashmap的資料結構,是老生常談了,面試的時候經常會被問道。底層資料結構為陣列+鍊錶+紅黑樹,儲存的是node節點,紅黑樹是treenode。
在進行put操作的時候,會呼叫putval方法進行儲存,在呼叫方法的時候,key會進行雜湊計算。
public v put(k key, v value)
static final int hash(object key)
然後看putval 方法做了哪些操作
final v putval(int hash, k key, v value, boolean onlyifabsent,
boolean evict)
// 如果找到相等的 進行替換
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
break;
p = e;}}
v oldvalue = e.value;
if (!onlyifabsent || oldvalue == null)
e.value = value;
afternodeaccess(e);
return oldvalue;}}
// 對hashmap 的操作進行增加
++modcount;
// 判斷 增加後的陣列長度是否大於臨界值 臨界值為當前資料長的0.75
if (++size > threshold)
// 進行擴容
resize();
afternodeinsertion(evict);
return null;
}
hashmap陣列中儲存的節點是node,如果轉換成紅黑樹,節點就是treenode,可以自己看一看這兩個節點。然後來到主要的方法resize()。resize同時包含初始化陣列和擴容的功能。
final node resize()
else if ((newcap = oldcap << 1) < maximum_capacity &&
oldcap >= default_initial_capacity)
newthr = oldthr << 1; // double threshold
}else if (oldthr > 0) // initial capacity was placed in threshold
newcap = oldthr;
else
if (newthr == 0)
// 新的擴容值
threshold = newthr;
// 建立陣列,初始化或者擴容
@suppresswarnings()
node newtab = (node)new node[newcap];
// 陣列新的拷貝
table = newtab;
// 如果陣列拷貝不是空,就是擴容,否則就是初始化 直接返回
if (oldtab != null)
else
} while ((e = next) != null); // 如果e節點下乙個不為null 繼續迴圈
// 判斷不為null
if (lotail != null)
if (hitail != null) }}
}}
// 返回樹
return newtab;
}
以上就是put 操作的過程。由此可知
1. 如果不進行put操作,hashmap底層不會進行建立陣列。put後進行初始化陣列,預設初始化陣列長度是16,擴容值為當前陣列長度的0.75。
(如果指定了長度,那麼擴容後,陣列長度也會是2的n次方,這樣是為了減少雜湊碰撞。)
2. 鍊錶長度如果大於等於7,(不是8),會進行轉換紅黑樹操作。在紅黑樹轉換方法裡,還會進行判斷陣列長度是否大於64,如果不大於,不轉換紅黑樹,進行擴容操作。否則進行轉換。(為了減少雜湊衝突)
3. 每次擴容,會進行當前陣列長度一倍的擴容,擴容值也進行一倍的增加。
get操作就不進行講解,就是通過key進行雜湊,計算在陣列的位置,然後如果是鍊錶,在煉表裡遍歷查詢。如果是紅黑樹,在紅黑樹裡遍歷查詢。
hashmap執行緒原因是會丟失資料,不會進行死迴圈。(也有可能是我測試的資料量太小)
具體原因是在擴容的時候。每次擴容,都會把當前節點拷貝出來,然後置null。如果a執行緒把節點資料獲取,然後置null;b執行緒就會獲取null資料,處理下乙個位置的資料,不管是哪個執行緒先完成擴容,都會丟失一部分資料。
而且不管是紅黑樹還是鍊錶,都會拆分成兩個,兩個執行緒同時拆分,同時賦值,也會造成後乙個執行緒會把前乙個執行緒的資料給覆蓋掉。
以上就是對hashmap的總結,如果有問題可以一起討論。
JDK1 8HashMap底層實現原理
預設初始容量 2 4 16 hashmap 底層陣列的長度總是 2 的 n 次方,這一點可參看後面關於 hashmap 構造器的介紹 當length 總是 2 的倍數時,h length 1 將是乙個非常巧妙的設計 假設 h 5,length 16,那麼 h length 1 將得到 5 如果 h ...
ThreadLocal 原始碼分析 jdk1 6
相信很多做分布式web開發的都封裝過這樣的乙個工具用來管理當前登入的使用者。在 裡面把使用者set進來 在controller 裡面get 出來使用 而且都是基於threadlocal 這個模板類來封裝的,出於好奇跟蹤進原始碼一 竟 這裡簡單寫個例子 public class baseloginco...
HashMap底層原理
1.hashmap概述 hashmap是基於雜湊表的map介面的非同步實現。此實現提供所有可選的對映操作,並允許使用null值和null鍵。此類不保證對映的順序,特別是它不保證該順序恆久不變。2.hashmap的資料結構 注意,迭代器的快速失敗行為不能得到保證,一般來說,存在非同步的併發修改時,不可...