自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

ConcurrentHashMap 如何秒殺 SynchronizedMap?

開發(fā) 前端
“SynchronizedMap 是對(duì)整個(gè) HashMap 加鎖,適用于低并發(fā)場景。而 ConcurrentHashMap 通過 分段鎖 + CAS 提高并發(fā)性能,在高并發(fā)環(huán)境下比 SynchronizedMap 更優(yōu)。并且,SynchronizedMap 允許 null 鍵值,而 ConcurrentHashMap 不允許?!?/div>

嗨,大家好,我是小米,一個(gè)熱愛分享技術(shù)的老碼農(nóng)(雖然不老,31歲正當(dāng)年!)。今天我們來聊聊 Java 面試中一道高頻問題:SynchronizedMap 和 ConcurrentHashMap 有什么區(qū)別?

這道題看似簡單,但其實(shí)暗藏玄機(jī),一不小心就容易掉坑。今天我們就通過一個(gè)故事 + 源碼剖析 + 性能對(duì)比,徹底搞清楚它們的區(qū)別。

故事開場:面試現(xiàn)場的靈魂拷問

某天,小王(5年Java開發(fā)經(jīng)驗(yàn))去參加阿里社招面試。

面試官看著簡歷,笑了笑:“你寫過高并發(fā)項(xiàng)目?”

小王點(diǎn)頭:“是的,我們系統(tǒng)日均 QPS 過百萬,主要用 HashMap 處理緩存?!?/p>

面試官挑了挑眉:“哦?那你能說說 SynchronizedMap 和 ConcurrentHashMap 的區(qū)別嗎?”

小王:“呃……它們都能保證線程安全……”

面試官:“嗯?那如果并發(fā)度很高,你會(huì)選哪個(gè)?”

小王開始緊張了:“這個(gè)……它們……嗯……”

面試官一笑:“好吧,我們換個(gè)問題……”

小王當(dāng)場淚目,回去后痛定思痛,決定徹底搞懂這兩個(gè)玩意兒!

那么,它們到底有什么區(qū)別呢?

SynchronizedMap vs ConcurrentHashMap 的核心區(qū)別

我們先來一個(gè)總結(jié)表格,直觀感受一下兩者的不同:

圖片圖片

看完表格,我們一個(gè)個(gè)拆解講解。

SynchronizedMap:簡單粗暴的“全局鎖”

首先,SynchronizedMap 其實(shí)是 Collections.synchronizedMap() 生成的,它的本質(zhì)是對(duì) HashMap 進(jìn)行“全局加鎖”,保證每次訪問都只能有一個(gè)線程進(jìn)入。

我們看看源碼(簡化版):

圖片圖片

內(nèi)部實(shí)現(xiàn)其實(shí)就是給 所有方法都加上 synchronized,讓所有操作串行化:

圖片圖片

這樣雖然保證了線程安全,但也導(dǎo)致每次操作都要獲取整個(gè) Map 的鎖,性能相當(dāng)?shù)?,在高并發(fā)環(huán)境下會(huì)變成性能瓶頸!

適用場景

適用于并發(fā)較低,或者讀多寫少的場景,比如:

  • 配置緩存
  • 線程數(shù)不多的 Web 應(yīng)用
  • 需要簡單線程安全的地方(例如同步讀取一小塊數(shù)據(jù))

如果是高并發(fā)環(huán)境,那就該換 ConcurrentHashMap 了!

ConcurrentHashMap:高并發(fā)神器

ConcurrentHashMap 是 Java 5 引入的,主要是為了提高并發(fā)性能。它的核心優(yōu)化點(diǎn)有兩個(gè):

  • 分段鎖(Segment)(JDK 1.7 之前)
  • CAS + 自旋鎖(JDK 1.8 之后)

讓我們看看 JDK 1.8 版本的 ConcurrentHashMap 怎么做到高性能的。

(1)底層結(jié)構(gòu)

在 JDK 1.8 之前,ConcurrentHashMap 采用 分段鎖(Segment),但 JDK 1.8 之后直接用 數(shù)組 + 鏈表 + 紅黑樹 代替了分段鎖,提高了效率。

  • 存儲(chǔ)結(jié)構(gòu):類似 HashMap,但每個(gè)桶(bucket)都是 鏈表 + 紅黑樹,高并發(fā)時(shí)可變成紅黑樹加速查詢。
  • 鎖機(jī)制:不鎖整個(gè) Map,而是只鎖住某個(gè) bucket,這樣多個(gè)線程可以同時(shí)訪問不同的 bucket,提高并發(fā)能力。
  • CAS(Compare And Swap):無鎖操作,提升性能。

(2)put() 方法解析

看源碼(簡化版):

圖片圖片

可以看到,它不會(huì)鎖整個(gè) Map,而是:

  • 先用 CAS 嘗試放入數(shù)據(jù),避免不必要的鎖競爭。
  • 如果 CAS 失敗,再只鎖住當(dāng)前 bucket,而不是整個(gè) Map,提高了并發(fā)性能。

適用場景

  • 高并發(fā)環(huán)境(推薦)
  • 大數(shù)據(jù)量存儲(chǔ)
  • 讀寫并重的場景
  • 緩存(如 LRU Cache)

性能對(duì)比實(shí)驗(yàn)

我們做個(gè)小實(shí)驗(yàn),對(duì)比兩者的性能(JMH 基準(zhǔn)測(cè)試):

圖片圖片

實(shí)驗(yàn)結(jié)果(吞吐量 ops/sec):

圖片圖片

可以看到,并發(fā)越高,SynchronizedMap 退化得越厲害,而 ConcurrentHashMap 能保持高性能。

總結(jié):面試高分回答

如果你在面試中遇到這個(gè)問題,你可以這樣答:

“SynchronizedMap 是對(duì)整個(gè) HashMap 加鎖,適用于低并發(fā)場景。而 ConcurrentHashMap 通過 分段鎖 + CAS 提高并發(fā)性能,在高并發(fā)環(huán)境下比 SynchronizedMap 更優(yōu)。并且,SynchronizedMap 允許 null 鍵值,而 ConcurrentHashMap 不允許。”

這下,面試官該對(duì)你點(diǎn)頭了吧?

責(zé)任編輯:武曉燕 來源: 軟件求生
相關(guān)推薦

2024-06-17 00:02:00

線程安全HashMapJDK 1.7

2020-10-14 07:20:53

高并發(fā)

2019-07-23 13:32:13

Java開發(fā)代碼

2020-08-13 08:17:50

MQ緩沖秒殺

2019-12-19 10:10:45

秒殺系統(tǒng)高并發(fā)

2015-06-15 10:12:36

Java原理分析

2020-09-01 07:47:32

Redis秒殺微信

2023-09-28 21:37:41

HashMap多線程

2019-11-18 08:21:04

秒殺系統(tǒng)高性能

2022-08-09 07:37:40

對(duì)象并發(fā)容器

2025-01-22 08:00:00

架構(gòu)秒殺系統(tǒng)Java

2022-07-18 08:02:16

秒殺系統(tǒng)后端

2021-04-27 08:54:43

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

2024-06-21 08:15:25

2019-11-12 15:11:45

秒殺流量高可用

2018-09-15 04:59:01

2018-06-24 08:40:21

秒殺架構(gòu)架構(gòu)優(yōu)化

2021-08-26 08:24:33

高并發(fā)秒殺系統(tǒng)

2023-08-22 20:43:09

HashMap單線程null

2024-06-04 08:32:40

點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)