成人无码视频,亚洲精品久久久久av无码,午夜精品久久久久久毛片,亚洲 中文字幕 日韩 无码

資訊專(zhuān)欄INFORMATION COLUMN

使用ConcurrentHashMap一定線程安全?

荊兆峰 / 2741人閱讀

摘要:前言老王為何半夜慘叫幾行代碼為何導(dǎo)致服務(wù)器爆炸說(shuō)好的線程安全為何還是出問(wèn)題讓我們一起收看今天的走進(jìn)正文出現(xiàn)背景說(shuō)到的出現(xiàn)背景,還得從說(shuō)起。在跟中,都只是調(diào)用的方法,各自都是原子操作,是線程安全的。

前言

老王為何半夜慘叫?幾行代碼為何導(dǎo)致服務(wù)器爆炸?說(shuō)好的線程安全為何還是出問(wèn)題?讓我們一起收看今天的《走進(jìn)IT》

正文
CurrentHashMap出現(xiàn)背景

說(shuō)到ConcurrentHashMap的出現(xiàn)背景,還得從HashMap說(shuō)起。

老王是某公司的苦逼Java開(kāi)發(fā),在互聯(lián)網(wǎng)行業(yè)中,業(yè)務(wù)總是迭代得非??臁sw現(xiàn)在代碼中的話,就是v1.0的模塊是單線程執(zhí)行的,這時(shí)候使用HashMap是一個(gè)不錯(cuò)的選擇。然而到了v1.5的版本,為了性能考慮,老王覺(jué)得把這段代碼改成多線程會(huì)更有效率,那么說(shuō)改就改,然后就愉快的發(fā)布上線了。

直到某天晚上,突然收到線上警報(bào),服務(wù)器CPU占用100%。這時(shí)候驚醒起來(lái)一頓排查(百度,谷歌),結(jié)果發(fā)現(xiàn)原來(lái)是HashMap 在并發(fā)的環(huán)境下進(jìn)行rehash的時(shí)候會(huì)造成鏈表的閉環(huán),因此在進(jìn)行g(shù)et()操作的時(shí)候?qū)е铝薈PU占用100%。喔,原來(lái)HashMap不是線程安全的類(lèi),在當(dāng)前的業(yè)務(wù)場(chǎng)景中會(huì)有問(wèn)題。那么你這時(shí)候又想到了Hashtable,沒(méi)錯(cuò),這是個(gè)線程安全的類(lèi),那我先用這個(gè)類(lèi)替換不就行了,一頓commit,push,部署上去了,觀察了一段時(shí)間,完美~再也沒(méi)出現(xiàn)過(guò)類(lèi)似的問(wèn)題了。

但是好日子過(guò)的并不長(zhǎng)久,運(yùn)營(yíng)的同事又找上門(mén)了,老王啊,XX功能怎么慢了這么多啊?這時(shí)候老王就納悶了,我沒(méi)改代碼啊?不就上次替換了一個(gè)Hashtable,難道這里會(huì)有效率的問(wèn)題?然后又是一頓排查(百度、谷歌),我去,果不其然,原來(lái)它線程安全的原因是因?yàn)樵诜椒ㄉ隙技恿藄ynchronized,導(dǎo)致我們?nèi)坎僮鞫即谢耍y怪這么慢。

經(jīng)過(guò)了2次掉陷阱的經(jīng)驗(yàn),這次的老王已經(jīng)是非常謹(jǐn)慎的去尋求更好的解決方案了,這時(shí)他找到ConcurrentHashMap,而且為了避免再次掉坑他也去提前了解了實(shí)現(xiàn)原理,原來(lái)這個(gè)類(lèi)是使用了Segment分段鎖,每一個(gè)Segment都有自己的鎖,這樣沖突的的范圍就變小了,效率也能提高不少。經(jīng)過(guò)調(diào)研發(fā)現(xiàn)確實(shí)不錯(cuò),于是他就放心的把Hashtable給替換掉了,從此運(yùn)營(yíng)再也沒(méi)來(lái)吐槽了,老王又過(guò)上了幸福的日子。

經(jīng)過(guò)一段時(shí)間緊張的業(yè)務(wù)開(kāi)發(fā),此時(shí)的項(xiàng)目已經(jīng)去到了v2.0,之前的ConcurrentHashMap相關(guān)的代碼已經(jīng)被改的面目全非,邏輯也復(fù)雜了很多,但項(xiàng)目還是按時(shí)順利的上線了。在項(xiàng)目在運(yùn)行了一段時(shí)間以后,居然再次出現(xiàn)線程安全的問(wèn)題,其根源竟然是ConcurrentHashMap,老王叕陷入了沉思...

為何會(huì)出問(wèn)題?

拋開(kāi)復(fù)雜的例子,我們用一個(gè)多線程并發(fā)獲取map中的值并加1,看看最后輸出的數(shù)字如何

public class CHMDemo {
    public static void main(String[] args) throws InterruptedException {
        ConcurrentHashMap map = new ConcurrentHashMap();
        map.put("key", 1);
        ExecutorService executorService = Executors.newFixedThreadPool(100);
        for (int i = 0; i < 1000; i++) {
            executorService.execute(new Runnable() {
                @Override
                public void run() {
                    int key = map.get("key") + 1; //step 1
                    map.put("key", key);//step 2
                }
            });
        }
        Thread.sleep(3000); //模擬等待執(zhí)行結(jié)束
        System.out.println("------" + map.get("key") + "------");
        executorService.shutdown();
    }
}

此時(shí)我們看看多次執(zhí)行輸出的結(jié)果

------790------
------825------
------875------

通過(guò)觀察輸出結(jié)果可以發(fā)現(xiàn),這段使用ConcurrentHashMap的代碼,產(chǎn)生了線程安全的問(wèn)題。我們來(lái)分析一下為什么會(huì)發(fā)生這種情況。在step1跟step2中,都只是調(diào)用ConcurrentHashMap的方法,各自都是原子操作,是線程安全的。但是他們組合在一起的時(shí)候就會(huì)有問(wèn)題了,A線程在進(jìn)入方法后,通過(guò)map.get("key")拿到key的值,剛把這個(gè)值讀取出來(lái)還沒(méi)有加1的時(shí)候,線程B也進(jìn)來(lái)了,那么這導(dǎo)致線程A和線程B拿到的key是一樣的。不僅僅是在

ConcurrentHashMap,在其他的線程安全的容器比如Vector之類(lèi)的也會(huì)出現(xiàn)如此情況,所以在使用這些容器的時(shí)候還是不能大意。

如何解決?

1、可以用synchronized

synchronized(this){
    //step1
    //step2
}

但是用這種方法的話,我們要考慮一下效率的問(wèn)題,會(huì)不會(huì)對(duì)當(dāng)前的業(yè)務(wù)影響很大?

2、用原子類(lèi)

public class CHMDemo {
    public static void main(String[] args) throws InterruptedException {
        ConcurrentHashMap map = new ConcurrentHashMap();
        AtomicInteger integer = new AtomicInteger(1);
        map.put("key", integer);
        ExecutorService executorService = Executors.newFixedThreadPool(100);
        for (int i = 0; i < 1000; i++) {
            executorService.execute(new Runnable() {
                @Override
                public void run() {
                    map.get("key").incrementAndGet();
                }
            });
        }
        Thread.sleep(3000); //模擬等待執(zhí)行結(jié)束
        System.out.println("------" + map.get("key") + "------");
        executorService.shutdown();
    }
}
------1001------

此時(shí)的輸出結(jié)果就正確了,效率上也比第一種解決方案提高很多。

結(jié)語(yǔ)

人生處處是陷阱,寫(xiě)代碼也是如此,多思考,多留心。

github:https://github.com/PeppaLittl...

推薦閱讀

《使用ConcurrentHashMap一定線程安全嗎?》
《大白話搞懂什么是同步/異步/阻塞/非阻塞》
《Java異常處理最佳實(shí)踐及陷阱防范》
《論JVM爆炸的幾種姿勢(shì)及自救方法》

有收獲的話,就點(diǎn)個(gè)贊吧

關(guān)注「深夜里的程序猿」,分享最干的干貨

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

轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/74256.html

相關(guān)文章

  • java中ConcurrentHashMap使用及在Java 8中的沖突方案

    摘要:中的使用及在中的沖突方案引言簡(jiǎn)稱(chēng)是在作為的替代選擇新引入的,是包的重要成員。為了解決在頻繁沖突時(shí)性能降低的問(wèn)題,中使用平衡樹(shù)來(lái)替代鏈表存儲(chǔ)沖突的元素。目前,只有和會(huì)在頻繁沖突的情況下使用平衡樹(shù)。 java中ConcurrentHashMap的使用及在Java 8中的沖突方案 1、引言 ConcurrentHashMap(簡(jiǎn)稱(chēng)CHM)是在Java 1.5作為Hashtable的替代選擇新...

    kun_jian 評(píng)論0 收藏0
  • 《Java Concurrency in Practice》中三個(gè)VehicleTracker例子的

    摘要:線程安全需求分析三個(gè)例子都是關(guān)于車(chē)輛追蹤的。他們使用了不同的方式來(lái)保證車(chē)輛追蹤類(lèi)的線程安全性。值得注意的值文檔也是維護(hù)線程安全的重要組成部分。 每個(gè)例子后面有代碼,大家可以先把代碼粘出來(lái)或者開(kāi)兩個(gè)頁(yè)面,先過(guò)一下例子的代碼,然后一邊看分析一遍看代碼,上下拖動(dòng)看的話效果不好。 歡迎拍磚和補(bǔ)充。 線程安全需求分析 三個(gè)例子都是關(guān)于車(chē)輛追蹤的。他們使用了不同的方式來(lái)保證車(chē)輛追蹤類(lèi)的線程安全性。...

    binaryTree 評(píng)論0 收藏0
  • [學(xué)習(xí)筆記-Java集合-7] Map - ConcurrentHashMap 源碼分析(一)

    摘要:簡(jiǎn)介是的線程安全版本,內(nèi)部也是使用數(shù)組鏈表紅黑樹(shù)的結(jié)構(gòu)來(lái)存儲(chǔ)元素。相比于同樣線程安全的來(lái)說(shuō),效率等各方面都有極大地提高。中的關(guān)鍵字,內(nèi)部實(shí)現(xiàn)為監(jiān)視器鎖,主要是通過(guò)對(duì)象監(jiān)視器在對(duì)象頭中的字段來(lái)表明的。 簡(jiǎn)介 ConcurrentHashMap是HashMap的線程安全版本,內(nèi)部也是使用(數(shù)組 + 鏈表 + 紅黑樹(shù))的結(jié)構(gòu)來(lái)存儲(chǔ)元素。 相比于同樣線程安全的HashTable來(lái)說(shuō),效率等各方...

    SoapEye 評(píng)論0 收藏0
  • 這幾道Java集合框架面試題在面試中幾乎必問(wèn)

    摘要:若遇到哈希沖突,則將沖突的值加到鏈表中即可。之后相比于之前的版本,之后在解決哈希沖突時(shí)有了較大的變化,當(dāng)鏈表長(zhǎng)度大于閾值默認(rèn)為時(shí),將鏈表轉(zhuǎn)化為紅黑樹(shù),以減少搜索時(shí)間。有序,唯一紅黑樹(shù)自平衡的排序二叉樹(shù)。 本文是最最最常見(jiàn)Java面試題總結(jié)系列第三周的文章。主要內(nèi)容: Arraylist 與 LinkedList 異同 ArrayList 與 Vector 區(qū)別 HashMap的底層...

    bigdevil_s 評(píng)論0 收藏0
  • 周末去面試,進(jìn)去 5 分鐘就出來(lái)了…

    摘要:記得,那是一個(gè)周末,棧長(zhǎng)去某知名互聯(lián)網(wǎng)公司面試,好像不到五分鐘,我就被面試官親切地趕出來(lái)了,當(dāng)時(shí)我那個(gè)尷尬,內(nèi)心深受打擊。。。 你們可能會(huì)想,棧長(zhǎng)這么菜的嗎?5分鐘都堅(jiān)持不了? 本文說(shuō)起來(lái)會(huì)有點(diǎn)尷尬,畢竟這是棧長(zhǎng)我曾經(jīng)經(jīng)歷過(guò)的故事。。。 那時(shí)候的棧長(zhǎng)還真菜,每天寫(xiě)著 if/ for 及一些簡(jiǎn)單的業(yè)務(wù)邏輯代碼,雖工作有些日子了,但技術(shù)水平還停留在剛畢業(yè)的起步階段。。。 記得,那是一個(gè)周末...

    pf_miles 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

閱讀需要支付1元查看
<