【Java EE】多線程-初階 synchronized 關鍵字 - 監視器鎖 monitor lock

synchronized 關鍵字 - 監視器鎖 monitor lock

  • 5. synchronized 關鍵字 - 監視器鎖 monitor lock
    • 5.1 synchronized 的特性
    • 5.2 synchronized 使??例
    • 5.3 Java 標準庫中的線程安全類

本節?標
? 掌握 synchronized關鍵字

5. synchronized 關鍵字 - 監視器鎖 monitor lock

(JVM 中采用的一個術語。使用鎖的過程中拋出一些異常,可能會看到 監視器鎖 這樣的報錯信息)

5.1 synchronized 的特性

(1) 互斥
synchronized 會起到互斥效果, 某個線程執?到某個對象的 synchronized 中時, 其他線程如果也執?到同?個對象 synchronized 就會阻塞等待.
? 進? synchronized 修飾的代碼塊, 相當于 加鎖
? 退出 synchronized 修飾的代碼塊, 相當于 解鎖
在這里插入圖片描述

synchronized用的鎖是存在Java對象頭?的
可以粗略理解成, 每個對象在內存中存儲的時候, 都存有?塊內存表?當前的 “鎖定” 狀態(類似于廁所的 “有?/??”).
如果當前是 “??” 狀態, 那么就可以使?, 使?時需要設為 “有?” 狀態.
如果當前是 “有?” 狀態, 那么其他??法使?, 只能排隊
在這里插入圖片描述

理解 “阻塞等待”.
針對每?把鎖, 操作系統內部都維護了?個等待隊列. 當這個鎖被某個線程占有的時候, 其他線程嘗試進?加鎖, 就加不上了, 就會阻塞等待, ?直等到之前的線程解鎖之后, 由操作系統喚醒?個新的線程,再來獲取到這個鎖.
注意:
? 上?個線程解鎖之后, 下?個線程并不是?即就能獲取到鎖. ?是要靠操作系統來 “喚醒”. 這也就是操作系統線程調度的?部分?作.
? 假設有 A B C 三個線程, 線程 A 先獲取到鎖, 然后 B 嘗試獲取鎖, 然后 C 再嘗試獲取鎖, 此時 B 和 C都在阻塞隊列中排隊等待。 但是當 A 釋放鎖之后, 雖然 B ? C 先來的, 但是 B 不?定就能獲取到鎖,?是和 C 重新競爭, 并不遵守先來后到的規則.

鎖, 本質上也是操作系統提供的功能,內核提供的功能 =>通過 api 給應用程序了。java (VM)對于這樣的系統 api 又進行了封裝.
synchronized 是調用 系統的 api 進行加鎖。系統 api 本質上是靠 cpu 上的特定指令完成加鎖
(2)可重?
synchronized 加鎖的效果,也可以稱為"互斥性。synchronized 還有一些其他特性:

理解 “把??鎖死”
?個線程沒有釋放鎖, 然后?嘗試再次加鎖.
// 第?次加鎖, 加鎖成功
lock();
// 第?次加鎖, 鎖已經被占?, 阻塞等待.
lock();
按照之前對于鎖的設定, 第?次加鎖的時候, 就會阻塞等待. 直到第?次的鎖被釋放, 才能獲取到第?個鎖. 但是釋放第?個鎖也是由該線程來完成, 結果這個線程已經躺平了, 啥都不想?了, 也就?法進?解鎖操作. 這時候就會 死鎖.
在這里插入圖片描述
這樣的鎖稱為 不可重?鎖

for (int i = 0; i < 50000; i++) {synchronized (locker) {synchronized (locker) {count++;}}
}

看起來是兩次一樣的加鎖,沒有必要。但是實際上開發中,很容易寫出這樣的代碼的。
在這里插入圖片描述
一旦方法調用的層次比較深,就搞不好容易出現這樣的情況
在這里插入圖片描述
要想解除阻塞,需要往下執行才可以,要想往下執行就需要等到第一次的鎖被釋放,這樣的問題,就稱為"死鎖”。
這樣的代碼在 Java 中其實是不會死鎖的!!! 為了避免程序猿粗心大意搞出死鎖!java引入了"可重入機制",Java 中的 synchronized 是 可重?鎖, 因此沒有上?的問題。

最外層“ { ”真正加鎖
最外層“ }” 真正解鎖
站在 JVM 的視角,看到多個}需要執行,JVM 如何知道哪個}是真正解鎖的那個??
先引入一個變量,計數器(0),每次觸發{的時候,把計數器++,每次觸發 } 的時候,把計數器 - -,當計數器 - - 為 0 的時候, 就是真正需要解鎖的時候~

在可重?鎖的內部, 包含了 “線程持有者” 和 “計數器” 兩個信息:(1)如果某個線程加鎖的時候, 發現鎖已經被?占?, 但是恰好占?的正是??, 那么仍然可以繼續獲取到鎖, 并讓計數器?增.(2)解鎖的時候計數器遞減為 0 的時候, 才真正釋放鎖. (才能被別的線程獲取到)
死鎖是面試中考察的重點,也是工作中,多線程開發中非常核心的注意事項~~
若面試官的問題:
如何自己實現一個可重入鎖?
1.在鎖內部記錄當前是哪個線程持有的鎖,后續每次加鎖,都進行判定
2.通過計數器,記錄當前加鎖的次數,從而確定何時真正進行解鎖,

死鎖(死鎖的進一步討論)
“死鎖”是多線程代碼中的一類經典問題, 加鎖是能解決線程安全問題,但是如果加鎖方式不當,就可能產生死鎖!!
死鎖同樣也是經典面試題!!
死鎖的三種典型場景
場景1. 一個線程, 一把鎖.
剛才說情況 如果鎖是不可重入鎖,并且一個線程針對一個鎖對象,連續加鎖兩次,就會出現死鎖(鑰匙鎖屋里了)
通過引入可重入鎖,問題就迎刃而解了
場景2. 兩個線程,兩把鎖
兩個線程,兩把鎖,每個線程獲取到一把鎖之后,嘗試獲取對方的鎖。線程1 獲取到 鎖A,線程2 獲取到 鎖B,接下來1 嘗試獲取 B,2 嘗試獲取 A,就同樣出現死鎖了!!!(屋鑰匙鎖車里了,車鑰匙鎖屋里了)
在這里插入圖片描述
如果不加 sleep, 很可能 t1 一口氣就把 locker1 和 locker2 都拿到了.這個時候,t2 還沒開動呢~ 自然無法構成死鎖.
經典面試題:讓你手寫一個出現死鎖的代碼:
C++方向,代碼就好寫,直接加鎖兩次就行了
Java 方向,就得通過上述代碼,兩個線程兩把鎖,精確控制好加鎖的順序在這里插入圖片描述
這里也就需要讓我們知道,如果遇到死鎖問題,就可以通過上述調用棧+狀態進行定位了
場景3. N 個線程 M 把鎖
一個經典的模型,哲學家就餐問題(學校的操作系統課上,也會有這個東西)在這里插入圖片描述
死鎖,非常嚴重的問題~~ 屬于程序中最嚴重的一類 bug !!!
一旦出現死鎖,線程就"卡住了"無法繼續工作,一個進程中的線程個數,就那么多。更可怕的是,死鎖這種bug, 往往都是概率 出現,測試的時候怎么測試都沒事,一發布就出問題,發布了也沒問題,等到夜深人靜,大家都睡著,突然給你整出點問題!比 bug 更可怕的是,“概率性出現的 bug”。雖然概率小,但是我們也需要重視!! 假設上述問題的 概率是 萬分之一,同樣是需要我們處理的,當時阿里這邊的服務器每天的訪問量是 3億次,每天就有 3萬個用戶,觸發了這個 bug!
如何避免死鎖問題?
教科書上經典的,死鎖的四個必要條件 !!!(下列四個條件,要求大家背下來!!面試經典問題!!)必要條件: 缺一不可!任何一個死鎖的場景,都必須同時具備上述四點,只要缺少一個,都不會構成死鎖。
1.鎖具有互斥特性.
一個線程拿到鎖之后,其他線程就得阻塞等待(鎖最基本的特性.,不太好破壞)
2.鎖不可搶占(不可被剝奪)
一個線程拿到鎖之后,除非他自己主動釋放鎖,否則別人搶不走~~(也是鎖最基本的特性.,也不好破壞)
3.請求和保持
一個線程拿到一把鎖之后,不釋放這個鎖的前提下,再嘗試獲取其他鎖。(如果先放下左手的筷子,再拿右手的筷子, 就不會構成死鎖! 代碼中加鎖的時候,不要去“嵌套”。這種做法, 通用性, 不夠的。 嵌套,很難避免:有些情況下,確實是需要拿到多個鎖, 再進行某個操作的.)
4.循環等待. 多個線程獲取多個鎖的過程中,出現了循環等待。A 等待 B, B 也等待 A 或者 A 等待 B,B 等待 C, C 等待 A。(約定好加鎖的順序(比如按照編號從小到大的順序),就可以破除循環等待了)
在這里插入圖片描述解決死鎖問題,核心思路, 破壞上述的必要條件,只要能破壞一個,就搞定!!上述破壞3 4兩種 是開發中比較實用的方法,還有一些其他方案,也能解決死鎖問題.但引入加鎖順序的規則(普適性高, 方案容易落地)
死鎖的小結
在這里插入圖片描述

死鎖這里非常重要的,時面試高頻的問題。
"談談你對于死鎖的理解”
死鎖:
1.死鎖是啥
2.死鎖的三個場景
3. 死鎖的危害
4.死鎖的必要條件, 如何解決死鎖

5.2 synchronized 使??例

synchronized 本質上要修改指定對象的 “對象頭”. 從使??度來看, synchronized 也勢必要搭配?個具體的對象來使?.
(1) 修飾代碼塊: 明確指定鎖哪個對象.
鎖任意對象

public class SynchronizedDemo {private Object locker = new Object();public void method() {synchronized (locker) {}}
}

鎖當前對象

public class SynchronizedDemo {public void method() {synchronized (this) {}}
}

(2) 直接修飾普通?法: 鎖的 SynchronizedDemo 對象

public class SynchronizedDemo {public synchronized void methond() {}
}

修飾一個普通方法,就可以省略"鎖對象。在這里插入圖片描述
等價于:
在這里插入圖片描述
(3) 修飾靜態?法: 鎖的 SynchronizedDemo 類的對象

public class SynchronizedDemo {public synchronized static void method() {}
}

synchronized 修飾普通方法, 相當于給 this 加鎖 (鎖對象 this)
synchronized 修飾靜態方法,相當于給類對象加鎖

我們重點要理解,synchronized 鎖的是什么.
兩個線程競爭同?把鎖, 才會產?阻塞等待.
兩個線程分別嘗試獲取兩把不同的鎖, 不會產?競爭.
在這里插入圖片描述

  1. 如果我一個線程加鎖,一個線程不加鎖,是否會存在線程安全問題?
    就不會出現鎖競爭了!!!會存在線程安全問題
  2. 如果兩個線程,針對不同的對象加鎖呢?
    也會存在線程安全問題
    在一個程序中,鎖,不一定只有一把。一個廁所,可能有多個坑位是一樣的。每個坑位都有一個鎖,如果你兩個線程,針對不同的坑位加鎖,不會產生互斥的(也稱為 鎖競爭/鎖沖突)。只有是針對同一個坑位加鎖,才有互斥。
    代碼中,可以創建出多個鎖。具體寫代碼的時候,想搞幾個鎖,就搞幾個。只有多個線程競爭同一把鎖,才會產生互斥,針對不同的鎖,則不會。
  3. 針對加鎖操作的一些混淆的理解
    把 count 放到一個 Test.t 對象中. 通過上述 add 方法來進行修改,加鎖的時候鎖對象,寫作 this
    在這里插入圖片描述
    synchronized (Test.class){ } 獲取類對象 :
    在這里插入圖片描述
    在這里插入圖片描述
    在 java 代碼中就可以通過類名.class 的方式拿到這個類對象。反射 api 就是從上述對象中獲取信息的。
    一個 java 進程中, 某個類,只能有唯一一個類對象
    在這里插入圖片描述
    在這里插入圖片描述
    synchronized 的變種寫法,可以使用 synchronized 修飾方法 。synchronized (this),也可以等價把 synchronized 加到方法上。在這里插入圖片描述
    在這里插入圖片描述
    方法中還有一個特殊的情況:
    static 修飾的方法,不存在 this.(static 修飾的方法,也叫做"類方法,不是針對"實例"的方法,而是針對類的,在這個方法中, 沒有 this.) 此時, synchronized 修飾 static 方法, 相當于針對類對象加鎖
    在這里插入圖片描述

其他編程語言中,加鎖解鎖, 都是單獨的方法。對比其他語言,java 的加鎖操作風格是獨樹一幟的。Java 中為啥使用 synchronized + 代碼塊 做法?而不是采用 lock + unlock 函數的方式來搭配呢?
像 C++ 這種寫法, 就可能會,忘記調用 unlock(unlock 沒有執行到),如果忘記調用 unlock 其他線程都無法獲取到這個鎖, 產生嚴重的 bug!!
Java 采取的 synchronized, 就能確保, 只要出了 } 一定能釋放鎖. 無論因為 return 還是因為 異常,無論里面調用了哪些其他代碼,都是可以確保 解鎖 操作執行到的.在這里插入圖片描述
只要我寫了 lock,就會立即加上 unlock 。這種說法,純純的,大豬蹄子行為,你給妹子保證,我這輩子只愛你一個,永遠不會變心。就算你非常細心,能夠確保每個 條件都加 unlock,但是你不能保證,你們組新來的實習生,也能做到這一點(各位同學們, 你們很可能就是這個實習生)
(其實在 Java 中,也有 lock/unlock 風格的鎖, 一般很少使用)
在這里插入圖片描述
但是c++沒有 finally ,只能靠程序猿人工來保證了~~(很有可能,java 程序員代碼早早寫完,也沒啥 bug, 下班回去打游戲了,C++ 程序員還在苦苦尋找哪里沒有釋放鎖)。但是更新版本的 C++ 引入了 lock quard (守衛)這個東西,可以起到類似于 synchronized,代碼塊結束之后,就能自動釋放鎖。

5.3 Java 標準庫中的線程安全類

  1. Java 標準庫中很多都是線程不安全的. 這些類可能會涉及到多線程修改共享數據, ?沒有任何加鎖措施.(把加鎖決策交給程序員)
    線程不安全.多個線程,嘗試修改同一個上述的對象,就很容易出現問題!! 而不是 100%,也可能你這個代碼寫出來之后,是沒問題的,具體代碼具體分析(多線程代碼,稍微變換一點,就可能有不一樣的結果)
    ? ArrayList
    ? LinkedList
    ? HashMap
    ? TreeMap
    ? HashSet
    ? TreeSet
    ? StringBuilder
  2. 但是還有?些是線程安全的. 使?了?些鎖機制來控制.
    自帶了鎖, 在多線程環境下時候,能好點。也不是 100% 不出問題!! 只是概率比上面小很多,具體代碼具體分析!!!(多線程代碼,稍微變換一點, 就可能有不一樣的結果)
    像Vector,HashTable,StringBuffer 這幾個類都屬于是 標準庫 即將棄用,不推薦使用,暫時還留著(保持和老的代碼兼容)。這個時候,新的代碼就不要用了,未來某一天新版本的 jdk,就把這些內容給刪了。
    ? Vector (不推薦使?)
    ? HashTable (不推薦使?)
    Java 早起,各位 Java 大佬還不夠成熟時,引入的設定。現在的話這些設定已經被推翻了,不建議使用了.
    ? ConcurrentHashMap
    相比于 HashTable 來說,高度優化的版本(后續詳細分析)
    ? StringBuffer
    StringBuffer 的核??法都帶有 synchronized .在這里插入圖片描述
    一旦代碼中, 使用了鎖,意味著代碼可能會因為鎖的競爭,產生阻塞=>程序的執行效率大打折扣.
    一定要思考清楚, 這個地方是否確食需要鎖,不需要的時候不要亂加.
    線程阻塞 =>從 cpu 上調度走,啥時候能調度回來繼續執行???不好說了~~ 滄海桑田
  3. 還有的雖然沒有加鎖, 但是不涉及 “修改”, 仍然是線程安全的
    ? String

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/93971.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/93971.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/93971.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Java多線程:從基礎到實戰

引言多線程是Java并發編程的核心技術之一&#xff0c;廣泛應用于服務器開發、數據處理、實時系統等領域。通過多線程&#xff0c;程序可以充分利用CPU資源&#xff0c;提高執行效率&#xff0c;同時處理多個任務。本文將從多線程的基本概念、實現方式、線程狀態、同步與通信到常…

list集合可以一邊遍歷一遍修改元素嗎?

今天看來一下Java中list集合部分的八股&#xff0c;發現了一個以前沒注意過的問題&#xff0c;記錄一下list可以一邊遍歷一邊修改元素嗎&#xff1f;答&#xff1a;在 Java 中&#xff0c;List在遍歷過程中是否可以修改元素取決于遍歷方式和具體的List實現類。①&#xff1a;對…

Infusing fine-grained visual knowledge to Vision-Language Models

Infusing fine-grained visual knowledge to Vision-Language Models Authors: Nikolaos-Antonios Ypsilantis, Kaifeng Chen, Andr Araujo, Ond?ej Chum Deep-Dive Summary: 視覺-語言模型中注入細粒度視覺知識 摘要 大規模對比預訓練產生了強大的視覺-語言模型&#xf…

RK3576賦能無人機巡檢:多路視頻+AI識別引領智能化變革

隨著工業巡檢任務的復雜度不斷提升&#xff0c;無人機逐漸取代傳統人工&#xff0c;成為電力、能源、林業、農業等行業的“高空作業主力”。然而&#xff0c;巡檢并非簡單的拍攝和回放&#xff0c;它要求無人機實時采集多路畫面、快速分析異常&#xff0c;并穩定回傳數據。這對…

ollama Modelfile 文件生成

輸入 根據如下TEMPLATE和params寫一個modelfile文件&#xff0c;TEMPLATE為&#xff1a;{{- $lastUserIdx : -1 -}} {{- range $idx, $msg : .Messages -}} {{- if eq $msg.Role “user” }}{{ $lastUserIdx $idx }}{{ end -}} {{- end }} {{- if or .System .Tools }}<|i…

關聯規則挖掘2:FP-growth算法(Frequent Pattern Growth,頻繁模式增長)

目錄 一、核心思想&#xff1a;一個形象的比喻 二、核心思想的具體拆解 步驟一&#xff1a;構建FP-tree&#xff08;頻繁模式樹&#xff09; 步驟二&#xff1a;從FP-tree中挖掘頻繁項集 為什么這很高效&#xff1f; 三、總結 核心思想與優勢 適用場景與缺點 四、例題…

在IDEA中DEBUG調試時查看MyBatis-Plus動態生成的SQL語句

在IDEA中DEBUG調試時查看MyBatis-Plus動態生成的SQL語句前言&#xff1a;動態SQL調試的痛與解決方案一、準備工作&#xff1a;調試前的檢查清單二、基礎方法&#xff1a;SqlSessionTemplate斷點調試步驟1&#xff1a;定位SqlSessionTemplate類步驟2&#xff1a;在invoke方法上設…

Linux 文本處理三劍客:awk、grep、sed 完全指南

Linux 文本處理三劍客&#xff1a;awk、grep、sed 完全指南 1. 概述 Linux 系統提供了三個強大的文本處理工具&#xff1a;awk、grep 和 sed&#xff0c;它們各有所長&#xff0c;結合使用可以高效地處理文本數據。 awk&#xff1a;擅長文本分析和格式化輸出&#xff0c;是一…

pyecharts可視化圖表組合組件_Grid:打造專業數據儀表盤

pyecharts可視化圖表組合組件_Grid&#xff1a;打造專業數據儀表盤 目錄pyecharts可視化圖表組合組件_Grid&#xff1a;打造專業數據儀表盤引言圖表1&#xff1a;Grid-Overlap-多X/Y軸示例代碼解析1. 圖表創建2. 多軸配置3. 圖表重疊4. Grid布局效果與應用圖表2&#xff1a;Gri…

【電氣工程學習】

三極管中&#xff1a;集電極C,基極B&#xff0c;發射極E接線&#xff1a;棕正藍負黑信號NPN開關輸出的是我們的0V,也叫低電平PNP開關輸出的是24V,也就是高電平&#xff08;NPN開關導通時&#xff0c;相當于把輸出端“拉”到0V&#xff08;低電平&#xff09;&#xff0c;稱為“…

【嵌入式】CAN通信

CAN 總線最初由博世于1980年代為汽車行業開發&#xff0c;能夠簡化復雜的布線網絡&#xff0c;還確保可靠和安全的數據傳輸。 1.CAN技術解釋 CAN網絡中的每個節點&#xff0c;都是平等的&#xff0c;沒有主次之分&#xff0c;這一點和SPI和I2C不同。每個節點都可以在需要的時…

Apache ShenYu網關與Nacos的關聯及如何配合使用

Apache ShenYu 網關與 Nacos 之間的關系可以概括為 “協作互補”:Nacos 作為 服務注冊與配置中心,為 ShenYu 提供動態的服務發現和配置管理能力,而 ShenYu 作為 流量網關,依賴 Nacos 實現路由信息的動態更新和實時生效。以下是詳細解析: 1. 核心關系圖解 拉取服務列表/路…

【CPP】一個CPP的Library(libXXXcore)和測試程序XXX_main的Demo

一個CPP的Library和測試程序Demo 1. 思路描述 目錄結構 總控CMakeList.txt文件 2. Library代碼實現 2.1 XXXLib.hpp文件(對外的接口定義文件)和XXXLib.cpp文件 2.1.1 XXXLib.hpp文件 2.1.2 XXXLib.cpp文件 2.2 CXXXLibApi.hpp文件和CXXXLibApi.cpp文件(內部的API基類) 2.2.1 CX…

【YashanDB認證】學習YashanDB的探索之路:從入門到實踐

在國產數據庫蓬勃發展的浪潮中&#xff0c;選擇了YashanDB作為技術學習的切入點。這不僅讓我深入了解了數據庫的核心技術&#xff0c;也讓我深刻體會到國產數據庫在性能、可靠性和生態適配上的創新價值。以下是我在學習YashanDB過程中的經驗與感悟。 一、YashanDB基礎介紹 Ya…

element UI 和 element plus 在組件上有哪些不同

Element UI 和 Element Plus 都是基于 Vue 的桌面端 UI 組件庫&#xff0c;由同一團隊&#xff08;餓了么前端團隊&#xff09;開發和維護。Element Plus 是 Element UI 的升級版&#xff0c;專為 Vue 3 設計&#xff0c;而 Element UI 僅支持 Vue 2。以下是它們在組件層面的主…

【3D重建技術】如何基于遙感圖像和DEM等數據進行城市級高精度三維重建?

城市級高精度三維重建是融合多源空間數據&#xff08;遙感圖像、DEM、GIS矢量等&#xff09;、計算機視覺與地理信息處理技術的復雜過程&#xff0c;核心目標是構建包含“地形地物&#xff08;建筑、道路、植被等&#xff09;”的真實、高精度三維場景。其流程可分為數據準備、…

【unitrix數間混合計算】3.4 無符號小數部分標記trait(bin_unsigned.rs)

一、源碼 這段代碼定義了一個類型級二進制小數系統&#xff0c;用于在編譯時表示和驗證二進制小數部分的有效性。 use crate::number::{F0, BFrac, Bit};/// 標記合法的二進制小數部分類型 pub trait BinFrac: Copy Default static {}// 空小數部分&#xff08;表示值為0&…

從一次 DDoS 的“死亡回放”看現代攻擊鏈的進化

本文記錄的是作者上周在測試環境真實踩到的坑。為了讓讀者能復現并親手體驗防御思路&#xff0c;文末給出了一份最小可運行的 Go 腳本&#xff0c;支持本地壓測 日志回放&#xff0c;方便對比加防護前后的差異。攻擊現場還原 周一凌晨 2:14&#xff0c;監控群里突然彈出告警&a…

LeetCode熱題100--101. 對稱二叉樹--簡單

1. 題目 給你一個二叉樹的根節點 root &#xff0c; 檢查它是否軸對稱。 示例 1&#xff1a;輸入&#xff1a;root [1,2,2,3,4,4,3] 輸出&#xff1a;true 示例 2&#xff1a;輸入&#xff1a;root [1,2,2,null,3,null,3] 輸出&#xff1a;false 2. 題解 /*** Definition for…

Pub/Sub是什么意思

Pub/Sub&#xff08;發布/訂閱模式&#xff09;?? 是一種異步消息通信范式&#xff0c;用于分布式系統中不同組件之間的解耦通信。它的核心思想是將消息的發送方&#xff08;發布者&#xff09;?? 和接收方&#xff08;訂閱者&#xff09;?? 分離&#xff0c;通過一個中間…