中文亚洲精品无码_熟女乱子伦免费_人人超碰人人爱国产_亚洲熟妇女综合网

當(dāng)前位置: 首頁 > news >正文

免費網(wǎng)站建設(shè)那個好鏈接檢測工具

免費網(wǎng)站建設(shè)那個好,鏈接檢測工具,網(wǎng)站建設(shè)的公司哪家好,渭南做網(wǎng)站哪家公司HashMap 之前寫了“Java集合TreeMap紅黑樹一生只愛一次”,說到底還是太年輕了,Map其實在排序中應(yīng)用比較少,一般追求的是速度,通過HashMap來獲取速度。hashmap 調(diào)用object hashcode方法用于返回對象的哈希碼,主要使用在…

HashMap

之前寫了“Java集合TreeMap紅黑樹一生只愛一次”,說到底還是太年輕了,Map其實在排序中應(yīng)用比較少,一般追求的是速度,通過HashMap來獲取速度。hashmap 調(diào)用object hashcode方法用于返回對象的哈希碼,主要使用在哈希表中。
public class HashMap<K,V> extends AbstractMap<K,V>implements Map<K,V>, Cloneable, Serializable
HashMap繼承AbstractMap 本質(zhì)是key-value鍵值對,具有Map素有常用的方法put() get() remove()。

Cloneable意味著可以被克隆。
實現(xiàn)serializable接口的作用是就是可以把對象存到字節(jié)流,然后可以恢復(fù)。
當(dāng)我們給put()方法傳遞鍵和值時,我們先對鍵調(diào)用hashCode()方法,返回的hashCode用于找到bucket位置來儲存Entry對象。

get

hashmap常用的get方法,可以看到先hash話,然后獲取

public V get(Object key) {Node<K,V> e;return (e = getNode(hash(key), key)) == null ? null : e.value;
}
static final int hash(Object key) {int h;return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
final Node<K,V> getNode(int hash, Object key) {Node<K,V>[] tab; Node<K,V> first, e; int n; K k;if ((tab = table) != null && (n = tab.length) > 0 &&(first = tab[(n - 1) & hash]) != null) {if (first.hash == hash && // always check first node((k = first.key) == key || (key != null && key.equals(k))))return first;if ((e = first.next) != null) {if (first instanceof TreeNode)return ((TreeNode<K,V>)first).getTreeNode(hash, key);do {if (e.hash == hash &&((k = e.key) == key || (key != null && key.equals(k))))return e;} while ((e = e.next) != null);}}return null;
}

put

在Java 8中put這個方法的思路分為以下幾步:

  1. 調(diào)用key的hashCode方法計算哈希值,并據(jù)此計算出數(shù)組下標(biāo)index
  2. 如果發(fā)現(xiàn)當(dāng)前的桶數(shù)組為null,則調(diào)用resize()方法進行初始化
  3. 如果沒有發(fā)生哈希碰撞,則直接放到對應(yīng)的桶中
  4. 如果發(fā)生哈希碰撞,且節(jié)點已經(jīng)存在,就替換掉相應(yīng)的value
  5. 如果發(fā)生哈希碰撞,且桶中存放的是樹狀結(jié)構(gòu),則掛載到樹上
  6. 如果碰撞后為鏈表,添加到鏈表尾,如果鏈表長度超過TREEIFY_THRESHOLD默認是8,則將鏈表轉(zhuǎn)換為樹結(jié)構(gòu)
  7. 數(shù)據(jù)put完成后,如果HashMap的總數(shù)超過threshold就要resize
public V put(K key, V value) {return putVal(hash(key), key, value, false, true);
}
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,boolean evict) {Node<K,V>[] tab; Node<K,V> p; int n, i;if ((tab = table) == null || (n = tab.length) == 0)n = (tab = resize()).length;if ((p = tab[i = (n - 1) & hash]) == null)tab[i] = newNode(hash, key, value, null);else {Node<K,V> e; K k;if (p.hash == hash &&((k = p.key) == key || (key != null && key.equals(k))))e = p;else if (p instanceof TreeNode)e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);else {for (int binCount = 0; ; ++binCount) {if ((e = p.next) == null) {p.next = newNode(hash, key, value, null);if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1sttreeifyBin(tab, hash);break;}if (e.hash == hash &&((k = e.key) == key || (key != null && key.equals(k))))break;p = e;}}if (e != null) { // existing mapping for keyV oldValue = e.value;if (!onlyIfAbsent || oldValue == null)e.value = value;afterNodeAccess(e);return oldValue;}}++modCount;if (++size > threshold)resize();afterNodeInsertion(evict);return null;
}

為什么非要使用紅黑樹呢?

這個選擇是綜合考慮的,既要put效率很高,同時也要get效率很高,紅黑樹就是其中一種。
二叉樹也ok,紅黑樹是一種自平衡的二叉查找樹
平衡二叉樹可以有效的減少二叉樹的深度,從而提高了查詢的效率
除了之外,紅黑樹還具備
節(jié)點是紅色或黑色;
根節(jié)點是黑色;
所有葉子都是黑色的空節(jié)點;
每個紅色節(jié)點必須有兩個黑色的子節(jié)點,也就是說從每個葉子到根的所有路徑上,不能有兩個連續(xù)的紅色節(jié)點;
從一個節(jié)點到該節(jié)點的子孫節(jié)點的所有路徑上包含相同數(shù)目的黑色節(jié)點
紅黑樹的優(yōu)勢在于它是一個平衡二叉查找樹,對于普通的二叉查找樹(非平衡二叉查找樹)在極端情況下可能會退化為鏈表的結(jié)構(gòu),再進行元素的添加、刪除以及查詢時,它的時間復(fù)雜度就會退化為 O(n)
紅黑樹的高度近似 log2n,它的添加、刪除以及查詢數(shù)據(jù)的時間復(fù)雜度為 O(logn)
紅黑樹時間復(fù)雜度比鏈表、二叉樹小,這就是采用紅黑樹做hashMap底層原理,然后在treeMap里面就更經(jīng)典了。

jdk1.7之前底層數(shù)據(jù)結(jié)構(gòu)采用哈希+鏈表。但后來業(yè)務(wù)越來越追求速度,hash的目的是為了得到進行索引,有些hash沖突可能造成死循環(huán),所以jdk1.8加上紅黑樹來解決明顯可以提高效率。
但是要分情況在數(shù)組長度大于64,同時鏈表長度大于8的情況下,鏈表將轉(zhuǎn)化為紅黑樹。當(dāng)數(shù)據(jù)的長度退化成6時,紅黑樹轉(zhuǎn)化為鏈表。數(shù)據(jù)長度沒有那么長,就沒必要采用紅黑樹,紅黑樹雖然提高了速度,但也提交了空間復(fù)雜度。數(shù)據(jù)長度大于8和數(shù)組長度大于64,采用紅黑樹。那為什么是6和8作為臨近值呢,其實這個值不要死記,是官網(wǎng)進行壓力測試的出來的結(jié)論。

為什么HashMap要擴容呢?

     數(shù)組是固定的,但集合是動態(tài)的,可以擴容。

當(dāng)hashmap越來越來多的元素塞進來之后,hashmap不得不擴容了,hashmap中元素個數(shù)超過160.75=12的時候,就把數(shù)組的大小擴展為216=32,即擴大一倍,然后重新計算每個元素在數(shù)組中的位置,而這是一個非常消耗性能的操作。
所以我們提前預(yù)測知道hashmap容量,再稍微設(shè)置大些,這樣可以減少性能的消耗的。
但是initialCapacity初始容量設(shè)置小了,會不會報錯呢?
不會的,但是hashmap會自動擴容,同樣也會走到上面過程,重新計算,消耗性能的操作。
提前預(yù)判,但是后來業(yè)務(wù)改變,需要那么大的容量,程序員應(yīng)該即使更改,要不然就和不設(shè)置沒有區(qū)別啦。

哈希 鏈表、紅黑樹 (來處理極端情況下的哈希碰撞)

數(shù)組+(鏈表或紅黑樹)Node類來存儲Key、Value

hashMap什么時候擴容?

注意,是在put的時候才會擴容,在容量超過四分之三的時候就會擴容

hashMap的key可以為空嗎

可以,Null值會作為key來存儲

key重復(fù)了,會被覆蓋嗎?

會的

HashMap擴容為什么總是2的次冪?

HashMap擴容主要是給數(shù)組擴容的,因為數(shù)組長度不可變,而鏈表是可變長度的。從HashMap的源碼中可以看到HashMap在擴容時選擇了位運算,向集合中添加元素時,會使用(n - 1) & hash的計算方法來得出該元素在集合中的位置。只有當(dāng)對應(yīng)位置的數(shù)據(jù)都為1時,運算結(jié)果也為1,當(dāng)HashMap的容量是2的n次冪時,(n-1)的2進制也就是1111111***111這樣形式的,這樣與添加元素的hash值進行位運算時,能夠充分的散列,使得添加的元素均勻分布在HashMap的每個位置上,減少hash碰撞

當(dāng)HashMap的容量是16時,它的二進制是10000,(n-1)的二進制是01111

JDk1.7HashMap擴容死循環(huán)問題

HashMap是一個線程不安全的容器,在最壞的情況下,所有元素都定位到同一個位置,形成一個長長的鏈表,這樣get一個值時,最壞情況需要遍歷所有節(jié)點,性能變成了O(n)。
JDK1.7中HashMap采用頭插法拉鏈表,所謂頭插法,即在每次都在鏈表頭部(即桶中)插入最后添加的數(shù)據(jù)。
死循環(huán)問題只會出現(xiàn)在多線程的情況下。

假設(shè)在原來的鏈表中,A節(jié)點指向了B節(jié)點。
在線程1進行擴容時,由于使用了頭插法,鏈表中B節(jié)點指向了A節(jié)點。
在線程2進行擴容時,由于使用了頭插法,鏈表中A節(jié)點又指向了B節(jié)點。
在線程n進行擴容時,
這就容易出現(xiàn)問題了。在并發(fā)擴容結(jié)束后,可能導(dǎo)致A節(jié)點指向了B節(jié)點,B節(jié)點指向了A節(jié)點,鏈表中便有了環(huán)

死循環(huán)解決方案:

1)、使用線程安全的ConcurrentHashMap替代HashMap,個人推薦使用此方案。

2)、使用線程安全的容器Hashtable替代,但它性能較低,不建議使用。

3)、使用synchronized或Lock加鎖之后,再進行操作,相當(dāng)于多線程排隊執(zhí)行,也會影響性能,不建議使用。

為了解決JDK1.7死循環(huán)問題,JDK1.8引入了紅黑樹
即在數(shù)組長度大于64,同時鏈表長度大于8的情況下,鏈表將轉(zhuǎn)化為紅黑樹。同時使用尾插法。當(dāng)數(shù)據(jù)的長度退化成6時,紅黑樹轉(zhuǎn)化為鏈表。

從JDK1.8開始,在HashMap里面定義了一個常量TREEIFY_THRESHOLD,默認為8。當(dāng)鏈表中的節(jié)點數(shù)量大于TREEIFY_THRESHOLD時,鏈表將會考慮改為紅黑樹
使用線程安全如Concurrenthashmap、HashTable

為什么線程不安全?

1、put的時候?qū)е碌亩嗑€程數(shù)據(jù)不一致。
這個問題比較好想象,比如有兩個線程A和B,首先A希望插入一個key-value對到HashMap中,首先計算記錄所要落到的桶的索引坐標(biāo),然后獲取到該桶里面的鏈表頭結(jié)點,此時線程A的時間片用完了,而此時線程B被調(diào)度得以執(zhí)行,和線程A一樣執(zhí)行,只不過線程B成功將記錄插到了桶里面,假設(shè)線程A插入的記錄計算出來的桶索引和線程B要插入的記錄計算出來的桶索引是一樣的,那么當(dāng)線程B成功插入之后,線程A再次被調(diào)度運行時,它依然持有過期的鏈表頭但是它對此一無所知,以至于它認為它應(yīng)該這樣做,如此一來就覆蓋了線程B插入的記錄,這樣線程B插入的記錄就憑空消失了,造成了數(shù)據(jù)不一致的行為。

2、另外一個比較明顯的線程不安全的問題是HashMap的get操作可能因為resize而引起死循環(huán)(cpu100%)
HashMap的擴容機制就是重新申請一個容量是當(dāng)前的2倍的桶數(shù)組,然后將原先的記錄逐個重新映射到新的桶里面,然后將原先的桶逐個置為null使得引用失效。HashMap之所以線程不安全,就是resize這里出的問題。

http://www.risenshineclean.com/news/47938.html

相關(guān)文章:

  • 軟件推薦網(wǎng)站溫州seo排名公司
  • 株洲網(wǎng)站建設(shè)什么是網(wǎng)站seo
  • 高端網(wǎng)站建設(shè)注意網(wǎng)絡(luò)營銷案例ppt
  • 深圳市seo網(wǎng)站設(shè)計多少錢國外服務(wù)器免費ip地址
  • adobe網(wǎng)站制作合肥正規(guī)的seo公司
  • 商業(yè)網(wǎng)站建設(shè)規(guī)劃書網(wǎng)絡(luò)營銷工具介紹
  • 電商網(wǎng)站用php做的嗎網(wǎng)絡(luò)營銷的表現(xiàn)形式有哪些
  • 網(wǎng)站虛擬主機購買教程seo公司網(wǎng)站推廣
  • 建設(shè)局網(wǎng)站施工合同范本上海網(wǎng)站建設(shè)哪家好
  • 企業(yè)網(wǎng)站建設(shè)開發(fā)費用seo基礎(chǔ)知識培訓(xùn)
  • 如何設(shè)計好的網(wǎng)頁杭州網(wǎng)站seo外包
  • 做私彩網(wǎng)站需注意什么電商怎么做新手入門
  • 可以做公司網(wǎng)站廊坊快速優(yōu)化排名
  • 做的網(wǎng)站在百度搜索不到怎么樣免費做網(wǎng)站
  • 重慶做網(wǎng)站開發(fā)的集中北京seo課程培訓(xùn)
  • 朔州如何做百度的網(wǎng)站網(wǎng)站排名查詢平臺
  • 團購網(wǎng)站如何優(yōu)化百度推廣免費
  • wordpress主題 小工具蘇州seo排名公司
  • 惠州網(wǎng)站建設(shè)效果業(yè)務(wù)多平臺怎么樣
  • 廬陽網(wǎng)站快速排名搜索引擎下載
  • 做網(wǎng)站優(yōu)化選阿里巴巴還是百度網(wǎng)絡(luò)營銷推廣策劃
  • 網(wǎng)站建設(shè)經(jīng)費預(yù)算seo廣告平臺
  • 跨境網(wǎng)絡(luò)專線多少錢一年網(wǎng)站seo方案案例
  • 永清縣建設(shè)局網(wǎng)站發(fā)稿軟文公司
  • 創(chuàng)業(yè)做網(wǎng)站 優(yōu)幫云品牌推廣方案怎么寫
  • 牌具網(wǎng)站廣告怎么做開一個免費網(wǎng)站
  • 網(wǎng)站虛擬主持百度域名收錄
  • 金融投資網(wǎng)站 php源碼aso推廣
  • 做網(wǎng)站的公司網(wǎng)站seo診斷分析和優(yōu)化方案
  • 國內(nèi)最新疫情福州seo服務(wù)