国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

HashMap源碼解析(JDK1.7)

svtter / 3256人閱讀

摘要:取模主要是為了能夠平均的落在每個數(shù)組上面。在多線程的情況下,會造成死循環(huán)。把先暫存單線程情況,創(chuàng)建一個對象參見方法,然后把引入給數(shù)組的位置。隊頭插入的效率高,如果隊尾插入,還要遍歷鏈表。此時,線程執(zhí)行以下代碼。

數(shù)據(jù)結(jié)構(gòu)

table,Entry類型數(shù)組的數(shù)據(jù)

Entry,包括了key,value,Entry,以及hash

final K key;
V value;
Entry next;
int hash;
put方法
public V put(K key, V value) {
    if (table == EMPTY_TABLE) {
        inflateTable(threshold);
    }
    if (key == null)
        return putForNullKey(value);//見putForNullKey方法
    int hash = hash(key);
    int i = indexFor(hash, table.length);//見indexFor方法,取模
    for (Entry e = table[i]; e != null; e = e.next) {//遍歷落在取模的數(shù)組上,遍歷鏈表
        Object k;
        if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {//判斷hash值一樣,并且key也要一樣
            V oldValue = e.value;
            e.value = value;
            e.recordAccess(this);
            return oldValue;
        }
    }

    modCount++;
    addEntry(hash, key, value, i);//見addEntry方法
    return null;
}
putForNullKey方法

key為空的情況,在數(shù)組的第一個位置的鏈表遍歷查找,如果有key為空,返回相應(yīng)的值,如果沒有,添加到鏈表后面。

private V putForNullKey(V value) {
    for (Entry e = table[0]; e != null; e = e.next) {
        if (e.key == null) {
            V oldValue = e.value;
            e.value = value;
            e.recordAccess(this);
            return oldValue;
        }
    }
    modCount++;
    addEntry(0, null, value, 0);
    return null;
}
indexFor方法

注釋已經(jīng)提醒了,length長度必須是2的非0冪數(shù),h & (length-1)是對h%length的意思(length長度為2的非0冪數(shù)時有效)。比如123243423 % 16的值是15,123243423 & 15也是15,當然123243423是我隨便打的。取模主要是為了能夠平均的落在每個數(shù)組上面。

static int indexFor(int h, int length) {
    // assert Integer.bitCount(length) == 1 : "length must be a non-zero power of 2";
    return h & (length-1);
}
addEntry方法
void addEntry(int hash, K key, V value, int bucketIndex) {
    //擴容為2倍長度,跟上面取模要求的一樣,乘以2也是2的非0冪數(shù)
    if ((size >= threshold) && (null != table[bucketIndex])) {
        resize(2 * table.length);
        hash = (null != key) ? hash(key) : 0;
        bucketIndex = indexFor(hash, table.length);
    }

    createEntry(hash, key, value, bucketIndex);//見createEntry方法
}
createEntry方法
void createEntry(int hash, K key, V value, int bucketIndex) {
    Entry e = table[bucketIndex];//取到數(shù)組的位置的entry
    table[bucketIndex] = new Entry<>(hash, key, value, e);//新entry加到鏈表的頭部,并把數(shù)組指向新entry
    size++;
}
/**
 * Creates new entry.
 */
Entry(int h, K k, V v, Entry n) {
    value = v;
    next = n;
    key = k;
    hash = h;
}
get方法
public V get(Object key) {
    if (key == null)
        return getForNullKey();
    Entry entry = getEntry(key);//見getEntry方法

    return null == entry ? null : entry.getValue();
}
getForNullKey方法
private V getForNullKey() {
    if (size == 0) {
        return null;
    }
    for (Entry e = table[0]; e != null; e = e.next) {//因為put的時候,直接放數(shù)組的第一個,所以查詢的時候,也查詢第一個
        if (e.key == null)
            return e.value;
    }
    return null;
}
getEntry方法
final Entry getEntry(Object key) {
    if (size == 0) {
        return null;
    }

    int hash = (key == null) ? 0 : hash(key);//先取hash
    for (Entry e = table[indexFor(hash, table.length)];//取模,找到數(shù)組位置,然后遍歷鏈表
         e != null;
         e = e.next) {
        Object k;
        if (e.hash == hash &&
            ((k = e.key) == key || (key != null && key.equals(k))))//判斷hash和key都相等
            return e;
    }
    return null;
}
transfer方法

這個方法在調(diào)用put的時候,在resize擴容的時候調(diào)用。在多線程的情況下,會造成死循環(huán)。

void transfer(Entry[] newTable, boolean rehash) {
    int newCapacity = newTable.length;
    for (Entry e : table) {
        while(null != e) {
            Entry next = e.next;//把next先暫存
            if (rehash) {
                e.hash = null == e.key ? 0 : hash(e.key);
            }
            int i = indexFor(e.hash, newCapacity);
            e.next = newTable[i];
            newTable[i] = e;
            e = next;
        }
    }
}
單線程情況:

1、put("a",1),創(chuàng)建一個entry對象(參見createEntry方法),然后把引入給數(shù)組0的位置。

2、put("b",1),再創(chuàng)建一個entry對象,然后新對象的next指向舊的entry對象,最后數(shù)組指向新entry。隊頭插入的效率高,如果隊尾插入,還要遍歷鏈表。


3、如果擴容到4,參加transfer方法,依然采用隊頭插入,也就是說,如果鏈表是1,2,3,4,那么插入后就變成4,3,2,1。
現(xiàn)創(chuàng)建一個表,取到鏈表數(shù)據(jù),開始遍歷。這里假設(shè)都到index為3的數(shù)組。

Entry next = e.next;//把next先暫存
e.next = newTable[i]時,這個e是key為b的entry
newTable[i] = e;執(zhí)行完后,index為3的數(shù)組執(zhí)行b。

現(xiàn)在執(zhí)行暫存的a
繼續(xù)執(zhí)行上面幾個步驟,完成擴容,結(jié)果如下:

多線程死循環(huán)情況:

我們設(shè)想一下,如果兩個線程同時進行擴容,A線程獲取key為b的entry的時候,時間分片到了,現(xiàn)在線程B線程執(zhí)行,完成上面單線程的情況。
此時,A線程執(zhí)行以下代碼。

e.next = newTable[i];
newTable[i] = e;
e = next;

e.next = newTable[i];的時候,此時b的next指向a

newTable[i] = e;的時候

可以看到,index為3的指向b,b的next指向a,a的next指向b。當有g(shù)et操作,并且hash也落在index為3的時候,就死循環(huán)了。

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://specialneedsforspecialkids.com/yun/75461.html

相關(guān)文章

  • Java集合之HashMap源碼解析

    摘要:之前,其內(nèi)部是由數(shù)組鏈表來實現(xiàn)的,而對于鏈表長度超過的鏈表將轉(zhuǎn)儲為紅黑樹。非線程安全,即任一時刻可以有多個線程同時寫,可能會導(dǎo)致數(shù)據(jù)的不一致。有時兩個會定位到相同的位置,表示發(fā)生了碰撞。 原文地址 HashMap HashMap 是 Map 的一個實現(xiàn)類,它代表的是一種鍵值對的數(shù)據(jù)存儲形式。 大多數(shù)情況下可以直接定位到它的值,因而具有很快的訪問速度,但遍歷順序卻是不確定的。 HashM...

    lindroid 評論0 收藏0
  • 集合源碼學(xué)習(xí)之路---hashMap(jdk1.8)

    摘要:值得位數(shù)有的次方,如果直接拿散列值作為下標訪問主數(shù)組的話,只要算法比較均勻,一般是很難出現(xiàn)碰撞的。但是內(nèi)存裝不下這么大的數(shù)組,所以計算數(shù)組下標就采取了一種折中的辦法,就是將得到的散列值與數(shù)組長度做一個與操作。 hashMap簡單介紹 hashMap是面試中的高頻考點,或許日常工作中我們只需把hashMap給new出來,調(diào)用put和get方法就完了。但是hashMap給我們提供了一個絕佳...

    kamushin233 評論0 收藏0
  • 一篇搞定基于JDK1.7,JDK1.8 HashMap、ConcurrentHashMap原理分析

    摘要:但是還會有統(tǒng)計數(shù)問題和數(shù)據(jù)丟失問題。中使用了保證線程安全,但是在中又把它優(yōu)化掉了,直接使用 一、開篇 HashMap、CurrentHashMap 面試時都要問爛了,用也用爛了。但是網(wǎng)上的解析要不就是不夠全面,要么就是copy來copy去,連基于JDK版本有的都很混亂。這篇文章帶你解析 基于jdk1.7、jdk1.8不同的hashMap和ConcurrentHashMap簡略分析(很多...

    Genng 評論0 收藏0
  • 前百度面試官整理的——Java后端面試題(一)

    摘要:發(fā)生了線程不安全情況。本來在中,發(fā)生哈希沖突是可以用鏈表法或者紅黑樹來解決的,但是在多線程中,可能就直接給覆蓋了。中,當同一個值上元素的鏈表節(jié)點數(shù)不小于時,將不再以單鏈表的形式存儲了,會被調(diào)整成一顆紅黑樹。 showImg(https://segmentfault.com/img/bVbsVLk?w=288&h=226); List 和 Set 的區(qū)別 List , Set 都是繼承自...

    JessYanCoding 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<