又開新坑o(*≧▽≦)ツ講講幾個Java版本的特性,先開始Java8,
HashMap的改進
HashMap采用哈希算法,先使用hashCode()判斷哈希值是否相同,如果相同,再使用equals(),如果再相同,則會替換掉原先的值,如不同則形成鏈表,后來的放前,原先的被擠到后面去,這種情況叫碰撞,我們應該要盡量避免這種情況,所以我們要通過改進hashCode()和equals(),當然我們無法完全避免這種情況。
為了不讓鏈表太長,HashMap提供了加載因子,0.75,當元素到達哈希表的75%時,進行擴容,如果設定到100%擴容,也許算出的哈希值就只有那幾個,比如長度為16的哈希表,一直只存3,5,7,8,其他的哈希值所在的位置無人問津,這樣就會產生很長的鏈影響性能。那么哈希值可以取很小嗎?也不可以,這樣會頻繁擴容,浪費空間。
一旦擴容,會將鏈表里的元素,每個重新計算新的位置,這樣碰撞概率就會變低。
即使有這種擴容機制,但是碰撞依舊避免不了,所以意味着效率變低,打個比方,在1.8之前Java采用數組+鏈表方式,如果產生了沖突情況,比如我找哈希值為3的值,就要從數組索引值為3的鏈表頭開始找,最糟糕的情況是找到這個鏈表的尾部,因此1.8將這種結構改進,變成數組+鏈表+紅黑樹 。
當鏈表上碰撞的個數大於8,總容量大於64,就會將鏈表轉換成紅黑樹,這樣的好處,除了添加,其他操作都要比鏈表快。
ConcurrentHashMap
1.7之前,並發級別默認為16,concurrentLevel=16;現在來介紹一下ConcurrentHashMap:
ConcurrentHashMap的數據結構是由一個Segment數組和多個HashEntry組成,主要實現原理是實現了鎖分離的思路解決了多線程的安全問題,如下圖所示:
Segment數組的意義就是將一個大的table分割成多個小的table來進行加鎖,也就是上面的提到的鎖分離技術,而每一個Segment元素存儲的是HashEntry數組+鏈表,這個和HashMap的數據存儲結構一樣。
ConcurrentHashMap 與HashMap和Hashtable 最大的不同在於:put和 get 兩次Hash到達指定的HashEntry,第一次hash到達Segment,第二次到達Segment里面的Entry,然后在遍歷entry鏈表。
JDK1.8的實現已經摒棄了Segment的概念,而是直接用Node數組+鏈表+紅黑樹的數據結構來實現,並發控制使用Synchronized和CAS來操作,整個看起來就像是優化過且線程安全的HashMap,雖然在JDK1.8中還能看到Segment的數據結構,但是已經簡化了屬性,只是為了兼容舊版本。
內存改進
內存分為三大塊,棧、堆、方法區,之前方法區其實屬於堆的永久區的一部分,可是我們平常都把它分開畫,因為JDK1.8取消這塊方法區,取而代之的是MetaSpace(元空間),最大特色是它直接使用物理內存,而不是使用分配內存,這說明垃圾回收機制運行機制概率變低,效率提升。也就是說OutOfMemoryError,幾乎不會發生。
既然如此,一些調優條件就無效了,比如PremGenSize、MaxPremGenSize,取而代之的是MetaspaceSize MaxMetaspaceSize
參考博文:
https://www.cnblogs.com/duanxz/p/3520829.html
https://www.jianshu.com/p/a7767e6ff2a2