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

資訊專欄INFORMATION COLUMN

趣談ConcurrentHashMap

Travis / 412人閱讀

摘要:最近準(zhǔn)備面試,一談到基礎(chǔ),大部分面試官上來就數(shù)據(jù)結(jié)構(gòu)素質(zhì)三連與區(qū)別,底層數(shù)據(jù)結(jié)構(gòu),為什么能保證線程安全。數(shù)組順序存儲,內(nèi)存連續(xù),查詢快,插入刪除效率稍微低,不過現(xiàn)在略有改善。而在開始,是由和的方式去實現(xiàn)高并發(fā)下的線程安全。

最近準(zhǔn)備面試,一談到j(luò)ava基礎(chǔ),大部分面試官上來就java數(shù)據(jù)結(jié)構(gòu)素質(zhì)三連:ArrayList與LinkedList區(qū)別,HashMap底層數(shù)據(jù)結(jié)構(gòu),ConcurrentHashMap為什么能保證線程安全。

剛畢業(yè)的應(yīng)屆生,或者基礎(chǔ)不好程序員(比如:本尊,對沒錯就是我~),只了解皮毛,一稍微深入就gg思密達(dá)。面試官:嗯...回頭等通知吧~ 基本一首《涼涼》送我到門外了。

不好意思,扯遠(yuǎn)了! 前兩個問題很簡單,一個數(shù)組一個鏈表。
數(shù)組順序存儲,內(nèi)存連續(xù),查詢快,插入刪除效率稍微低(System.copyArray),不過現(xiàn)在略有改善。
鏈表插入刪除快速高效,查詢效率差了點意思,存儲不連續(xù)。
總之,各有利弊吧,根據(jù)業(yè)務(wù)場景選擇適合自己的存儲結(jié)構(gòu),不過現(xiàn)在也出現(xiàn)很多類似的改進(jìn)版本,暫時不談了(其實我也沒了解過,啊哈哈哈~有點尷尬)
HashMap JDK1.8以前基本都是數(shù)組+鏈表實現(xiàn),JDK1.8開始改為數(shù)組+列表,當(dāng)列表長度大于某個值(具體忘了),鏈表轉(zhuǎn)化為一個X爆了的數(shù)據(jù)結(jié)構(gòu)————紅黑樹(我都嚇尿了反正,看了幾百遍沒記住這玩意各種算法)

其實今天主要是想聊一下這個叫做ConcurrentHashMap的數(shù)據(jù)結(jié)構(gòu),看過網(wǎng)上幾篇文章實在是看的蛋疼,一來寫的一般,對于源碼的復(fù)制粘貼,最為我看起來吃力;二來紅黑樹太難,看著難受的一比。是在無法理解這個數(shù)據(jù)結(jié)構(gòu)的精髓所在,故而想自己寫篇文章來記錄自己學(xué)習(xí)的過程,就好比孫悟空去了一趟五指山下,做個標(biāo)記!

廢話少說直接先上jb:

如圖所示,相比傳統(tǒng)HashMap,jdk1.8之前 ConcurrentHashMap 在傳統(tǒng)HashEntry之前增加了一個segment數(shù)組。Segment數(shù)組的意義就是將一個大的table分割成多個小的table來進(jìn)行加鎖,Segment數(shù)組中每一個元素就是一把鎖,每一個Segment元素存儲的是HashEntry數(shù)組+鏈表。而在jdk1.8開始,ConcurrentHashMap是由CAS和Synchronized的方式去實現(xiàn)高并發(fā)下的線程安全。

我們主要從的get,put等方法來學(xué)習(xí)ConcurrentHashMap,是如何插入和獲取元素,以及如何保證線程安全。
先看下get方法源碼:

public V get(Object key) {
        Node[] tab; Node e, p; int n, eh; K ek;
        int h = spread(key.hashCode());
        if ((tab = table) != null && (n = tab.length) > 0 &&
            (e = tabAt(tab, (n - 1) & h)) != null) {
            if ((eh = e.hash) == h) {
                if ((ek = e.key) == key || (ek != null && key.equals(ek)))
                    return e.val;
            }
            else if (eh < 0)
                return (p = e.find(h, key)) != null ? p.val : null;
            while ((e = e.next) != null) {
                if (e.hash == h &&
                    ((ek = e.key) == key || (ek != null && key.equals(ek))))
                    return e.val;
            }
        }
        return null;
    }

我看上面的代碼好多中間變量,很影響我這種菜鳥分析邏輯,于是我按照自己的編碼風(fēng)格,重寫了一下:

  public V get(Object key) {
        int h = (key.hashCode() ^ (key.hashCode() >>> 16)) & 0x7fffffff;// 2 ^31 -1
        Node[] tab = table;
        // 一般對哈希表的散列很自然地會想到用hash值對length取模(即除法散列法)
        // Hashtable中也是這樣實現(xiàn)的,這種方法基本能保證元素在哈希表中散列的比較均勻,
        // 但取模會用到除法運算,效率很低,HashMap中則通過h&(length-1)的方法來代替取模,
        // 同樣實現(xiàn)了均勻的散列,但效率要高很多,這也是HashMap對Hashtable的一個改進(jìn)。
        Node e = tabAt(tab, (tab.length - 1) & h);
        if (tab == null || tab.length <= 0 ||e == null) {
            return null;
        }
        if (e.hash == h) {
            if (e.getKey() == key || (e.getKey() != null && key.equals(e.getKey()))){
                return e.getValue();                
            }
        } else if (e.hash < 0) {
            Node p = e.find(h, key);
            return p!= null ? p.getValue() : null;
        }
        e = e.next;
        while (e != null) {
            if (e.hash != h) {
                return null;
            }
            if (e.getKey() == key || (e.getKey() != null && key.equals(e.getKey())))
                return e.getValue();
        }
        return null;
    }
int h = (key.hashCode() ^ (key.hashCode() >>> 16)) & 0x7fffffff;// 2 ^31 -1

代碼的意思————通過哈希值二進(jìn)制異或該哈希值二進(jìn)制右移動16位 是為了計算哈希值 再和 上面那玩意進(jìn)行與運算并不知道是什么鬼。如下圖:

計算出Hash值之后要通過hash值找到對應(yīng)數(shù)組的下標(biāo)進(jìn)而找到數(shù)組元素:

Node e = tabAt(tab, (tab.length - 1) & h);

(tab.length - 1) & h 根據(jù)計算出來的hash值從HashMap的“骨干”——bucket數(shù)組找到對應(yīng)的bucket
java.util.HashMap (ConcurrentHashMap同樣)保證bucket數(shù)組的長度是2的冪方,所以本來應(yīng)該寫成:
index = n % length的,變?yōu)榭梢詫懗桑篿ndex = n & (length - 1) ,“&”效率會高一點。

說了這么多我們來看下tabAt方法:

public static int numberOfLeadingZeros(int i) {
    // HD, Figure 5-6
    if (i == 0)
        return 32;
    int n = 1;
    if (i >>> 16 == 0) { n += 16; i <<= 16; }
    if (i >>> 24 == 0) { n +=  8; i <<=  8; }
    if (i >>> 28 == 0) { n +=  4; i <<=  4; }
    if (i >>> 30 == 0) { n +=  2; i <<=  2; }
    n -= i >>> 31;
    return n;
}
U = sun.misc.Unsafe.getUnsafe(); // 獲取unsafe類的實例 單例模式
@CallerSensitive
public static Unsafe getUnsafe() {
    Class arg = Reflection.getCallerClass();//獲取調(diào)用者方法的類
    if (!VM.isSystemDomainLoader(arg.getClassLoader())) {
        throw new SecurityException("Unsafe");
    } else {
        return theUnsafe;
    }
}
Class ak = Node[].class;
ABASE = U.arrayBaseOffset(ak);
int scale = U.arrayIndexScale(ak);
ASHIFT = 31 - Integer.numberOfLeadingZeros(scale);

@SuppressWarnings("unchecked")
static final  Node tabAt(Node[] tab, int i) {
    return (Node)U.getObjectVolatile(tab, ((long)i << ASHIFT) + ABASE);
}




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

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

相關(guān)文章

  • PHP算法趣談--猴子找大王

    摘要:一算法問題將一群猴子排成一圈,按照猴子數(shù)按照依次編號。在計算機(jī)編程的算法中,類似問題又稱為約瑟夫環(huán)。問題是,給定了和,一開始要站在什么地方才能避免被處決四算法設(shè)計與實現(xiàn)算法問題存猴子名稱給猴子定義名稱定義猴子排序個數(shù) 一、算法問題 將一群猴子排成一圈,按照猴子數(shù)按照1,2,...,n依次編號。然后從第1只開始數(shù),定義數(shù)m個猴子,之后將數(shù)到的猴子將它踢出圈,從它后面再開始數(shù), 再數(shù)到第m...

    FuisonDesign 評論0 收藏0
  • 備胎的自我修養(yǎng)——趣談 JavaScript 中的 ASI (Automatic Semicolon

    摘要:行結(jié)束符之后的符號有二義性,使得該符號與上條語句能夠無縫對接,不導(dǎo)致語法錯誤。然而在中,有幾種特殊語句是不允許行結(jié)束符存在的。如果語句中有行結(jié)束符,會優(yōu)先認(rèn)為行結(jié)束符表示的是語句的結(jié)束,這在標(biāo)準(zhǔn)中稱為限制產(chǎn)生式。 showImg(https://segmentfault.com/img/bVmyZB); 什么是 ASI ? 自動分號插入 (automatic semicolon i...

    _ipo 評論0 收藏0
  • ConcurrentHashMap探究

    摘要:是線程安全,性能出色的的線程安全實現(xiàn),相比較他是線程安全的,相比較他的性能優(yōu)勢非常明顯。的源碼其實很簡單,和的結(jié)構(gòu)一致,但是每一個方法都是用來修飾,以保證操作是線程安全的。這樣在多線程的情況下,只有一個線程獲取鎖操作中的數(shù)據(jù)。 ConcurrentHashMap ConcurrentHashMap是線程安全,性能出色的Map的線程安全實現(xiàn),相比較HashMap他是線程安全的,相比較Ha...

    zombieda 評論0 收藏0
  • JDK1.8下ConcurrentHashMap的一些理解(一)

    摘要:如下代碼省略相關(guān)代碼省略相關(guān)代碼可以看到在里面,是直接采用數(shù)組鏈表紅黑樹來實現(xiàn),時間復(fù)雜度在和之間,如果鏈表轉(zhuǎn)化為紅黑樹了,那么就是到。 在JDK1.8里面,ConcurrentHashMap在put方法里面已經(jīng)將分段鎖移除了,轉(zhuǎn)而是CAS鎖和synchronized ConcurrentHashMap是Java里面同時兼顧性能和線程安全的一個鍵值對集合,同屬于鍵值對的集合還有Hash...

    Andrman 評論0 收藏0
  • HashMap ConcurrentHashMap

    摘要:與中的類似,也是一個數(shù)組加鏈表,不過這個線程安全。線程安全,但是它的線程安全是依賴將所有修改的代碼塊都用修飾。這是中實現(xiàn)線程安全的思路,由個組成,每個就相當(dāng)于一個數(shù)組鏈表。線程安全,但性能差,不推薦使用。 問題描述 翻翻別人的面試經(jīng)歷 這里在知乎上看到的,分享出了自己面試阿里Java崗的面試題。 showImg(https://segmentfault.com/img/bVbfSZ5?...

    forrest23 評論0 收藏0

發(fā)表評論

0條評論

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