併發工具類的「坑」,你遇到過哪些?

2022-03-19 05:07:25 字數 1629 閱讀 4980

在我們小夥伴與同事朋友討論時,我們有時會聽到有關執行緒安全和併發工具的一些片面的觀點和結論。

比如「把 hashmap 改為 concurrenthashmap,就可以解決併發問題了呀」「要不我們試試無鎖的 copyonwritearraylist 吧,效能更好」和「存在併發問題?加鎖就可以了呀」等等等....

其實,事實並沒有那麼簡單~

大家都知道,jdk1.5之後推出concurrenthashmap,是乙個高效能的執行緒安全的雜湊表容器。

可能大家會認為,這是乙個很好地解決併發的工具,其實並不然。

「執行緒安全」這四個字特別容易讓人誤解,因為 concurrenthashmap 只能保證提供的原子性讀寫操作是執行緒安全的。

在一些我們實際的業務開發場景中,如果我們一昧的去使用,而不去剖析,這樣「bug」 就會找到你~

有個map已經儲存900個元素,現在要在增加100個元素,size為1000。增加100個元素,我們需要10個執行緒併發執行。

可能有小夥伴會不假思索的來用concurrenthashmap,認為不會出現什麼併發問題。

小明(假設人物)看到需求,覺得不是什麼問題,於是使用concurrenthashmap來操作。

**邏輯:在每乙個執行緒的**邏輯中先通過 size 方法拿到當前元素數量,計算 concurrenthashmap 目前還需要補充多少元素,並在日誌中輸出了這個值,然後通過 putall 方法把缺少的元素新增進去。起始元素個數和最終元素個數日誌列印。

小明信心滿滿去自測,看了日誌他傻眼了,如下:

從日誌中可以看到:

那麼為什麼會出現這些種種問題呢? 讓我們繼續look。

針對這個問題,我們假設乙個場景:搬磚(不是碼農搬磚哦)。工地上,有個卡車要從工地拉走一車磚,車的容量可裝1000塊磚,10位打工人同時搬磚。打工人辛苦一上午已經完工90%,還有僅剩的100塊。concurrenthashmap就是這個車本身,可以確保多個打工人在搬磚時,不會相互影響干擾,但無法確保打工人 a 看到還需要裝 100 塊磚但是還未裝的時候,工人 b 就看不到車中的磚數量。更重要的是搬磚這個操作不是原子性的,別人看起來可能車裡一下變成了944、964等,還需要補不一樣的數量。 

回到咱們的concurrenthashmap,對映出:

有兩種解決方法,在這裡都列舉一下:

1. 直接針對concurrenthashmap加上鎖synchronized。這種全程concurrenthashmap加鎖,可能發揮不到concurrenthashmap的效率最大化。

2. 使用concurrenthashmap 的原子性方法 computeifabsent 來做復合邏輯操作,判斷 key 是否存在 value,如果不存在則新建立乙個 longadder 物件,最後返回 value。由於 computeifabsent 方法返回的 value 是 longadder,是乙個執行緒安全的累加器,因此可以直接呼叫其 increment 方法進行累加。

經過小明同學的不懈努力,終於將**效率提公升了乙個檔次,安全問題解決,同時得到了領導對他的認可。

謝謝各位支援!

欲知copyonwritearraylist有什麼坑,請看下章分析。

資料治理的坑你遇到過幾個?

資料治理的坑你遇到過幾個?朱瑞 御數坊 5月23日 資料治理是一項長期而繁雜的工作,很多時候大家都為如何做好資料治理而感到困惑,甚至很多時候對此失去了信心。筆者從事企業資訊化工作有11年以上的時間了,涉及資料治理相關的工作也有7年的時間。在這些年的實踐當中有成功的經驗,當然也經歷過很多失敗的教訓,有...

微信支付遇到過的坑

首先先來看下圖 流程如下 後台獲取訂單資訊,生成簽名 簽名必須按照簽名規範,請參照 qq簽名前字串如下 注意 用md5加密後將字母轉為大寫 3.將簽名引數和生成的簽名轉為xml格式,如下 jsapi支付測試body 10000100mch id 1add1a30ac87aa2db72f57a2375...

異常處理遇到過的那些坑

今年有個目標之一就是提公升團隊 的質量,所以時常會思索如何把這件事做到更好,不想教條主義,也不想搞出乙個 規範,強制團隊照著做,落地的效果不好,反而把大家的積極性給弄沒了。所以我的原則是,我們一起看看什麼事是我們不能做的,排除掉,剩下的就是我們可以做的,同時真正搞清楚問題在 而不是簡單的模仿。從我個...