HashMap的初始容量html
背景java
不少人能夠把HashMap的原理描述的很溜。好比JDK1.7以前,底層數據結構是數組+鏈表。JDK1.8以後,出於效率上的考慮,在數組長度大於64,鏈表長度大於8的時候,會轉換爲紅黑樹。數據庫
甚至知道對於賦值了容量的都會作一個變成2的n次方的操做。它的hash方法爲了防止高位變化大或者低位變化大將它自己hash值右移16位和自身原hash值作一個按位異或操做再與容量-1作按位與。還知道默認的負載因子是0.75,這個值是通過幾率論統計出來的,最好不要改。數組
瞭解的這麼清楚,我就想問一下爲何從數據庫中取出來一個list,以後轉換成hashmap。直接用的是Map map = new HashMap()或者是Map map = Maps.newHashMap(),爲何不賦初始容量呢?數據結構
分析oracle
容量的大小會在put過程當中發生resize操做。若是初始不賦值。默認容量是16。那好比從數據庫中取出來1000個元素。put過程當中會從16->32->64->128……,運行屢次resize操做。resize操做數組,須要將全部元素進行復制和rehash,效率是很低的。jvm
因此也有一些同窗考慮到這個問題,代碼是這麼寫的: Map map = new HashMap(list.size());性能
這個寫法也有問題,由於resize並非到達容量上限才resize。爲了儘可能避免hash衝突,是超過閾值threshold就擴容。而這個threshold=容量*負載因子。3d
因此我更建議的寫法是Map map = new HashMap(list.size()/負載因子)。htm
這樣理論上能夠比Map map = new HashMap(list.size())減小一次resize。
總結
在能夠肯定HashMap容量時,最好Map map = new HashMap(list.size()/負載因子)來初始化,避免自動擴容帶來的性能損耗。
思考
ConcurrentHashMap怎麼來更合理的初始化?
JVM內存結構和Java內存模型
背景
前段時間偶然看到有篇文章批判不少人對「JVM內存模型」這個概念不清楚,說這個經典的圖並非內存模型而是內存結構。
而內存模型應該是JSR133規範裏介紹的volatile、final和synchronized等關鍵字的內存語義。
分析
這個很是富有淘金式思惟的做者卻搞混了一個概念,看看下面JSR-133規範裏是怎麼說的:JSR133規範裏講的Java內存模型,並無說是JVM的內存模型啊。
Java內存模型講的是Java語言自己的規範,這個規範包含了各個Java標準關鍵字在JVM裏是怎樣運做的。而JVM內存模型描述的是Java虛擬機怎樣運行字節碼的。因此上面經典的圖說是JVM內存模型也不爲過。不過根據官網,叫JVM內存結構更爲標準。證據以下:
https://docs.oracle.com/javase/specs/jvms/se14/html/jvms-2.html#jvms-2.5
在oracle官網裏,介紹了這個概念
總結
Java內存模型和JVM內存模型是兩個概念。