<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      Loading

      【Java】Synchronized-你知道Java是如何上鎖的嗎?

      Synchronized鎖獲取與升級(jí)流程——從偏向鎖到重量級(jí)鎖

      synchronized 關(guān)鍵字是 Java 并發(fā)編程的元老,很多人對(duì)它的印象還停留在“重量級(jí)”、“性能差”。但從 JDK 1.6 開始,synchronized 引入了鎖升級(jí)機(jī)制,使其變得非常智能。

      這套機(jī)制的核心思想是“按需分配”,在無競爭或低競爭時(shí)提供極高的性能,只在競爭激烈時(shí)才退化為傳統(tǒng)的重量級(jí)鎖。它的升級(jí)路徑如下,并且此過程不可逆(只能升級(jí),不能降級(jí)):

      無鎖 → 偏向鎖 → 輕量級(jí)鎖 → 重量級(jí)鎖

      1. 無鎖狀態(tài) (No Lock)

      一個(gè)對(duì)象在剛被創(chuàng)建時(shí),其對(duì)象頭的 Mark Word 中沒有任何鎖信息,此時(shí)它就處于無鎖狀態(tài)。

      2. 偏向鎖 (Biased Lock)

      升級(jí)時(shí)機(jī):當(dāng)?shù)谝粋€(gè)線程訪問同步代碼塊時(shí),鎖會(huì)升級(jí)為偏向鎖。
      核心機(jī)制:
      通過 CAS (Compare-And-Swap) 操作,將當(dāng)前線程的 ID 記錄在對(duì)象頭的 Mark Word 中。
      此后,該線程再次進(jìn)入或退出同步塊時(shí),不再需要進(jìn)行任何 CAS 操作,只需簡單檢查 Mark Word 中的線程 ID 是否是自己。
      目標(biāo)場景:適用于只有一個(gè)線程會(huì)訪問同步代碼塊的場景。這大大減少了加鎖的開銷,性能幾乎等同于無鎖。

      3. 輕量級(jí)鎖 (Lightweight Lock)

      升級(jí)時(shí)機(jī):當(dāng)?shù)诙€(gè)線程嘗試獲取這個(gè)偏向鎖時(shí),偏向鎖模式宣告結(jié)束,進(jìn)入偏向鎖撤銷(Bias Revocation)流程,并升級(jí)為輕量級(jí)鎖。
      核心機(jī)制:
      線程在自己的棧幀中創(chuàng)建一塊名為 Lock Record 的空間,用于拷貝對(duì)象頭的 Mark Word(Displaced Mark Word)。
      通過 CAS 操作,嘗試將對(duì)象頭的 Mark Word 更新為指向這個(gè) Lock Record 的指針。
      如果 CAS 成功,則獲取鎖成功。如果失敗,線程會(huì)進(jìn)行自適應(yīng)自旋(Adaptive Spinning),即在原地循環(huán)一小段時(shí)間,而不是立即掛起,期待鎖能很快被釋放。
      目標(biāo)場景:適用于線程交替執(zhí)行同步代碼塊,且每次持有鎖的時(shí)間很短的場景。自旋避免了線程掛起和喚醒帶來的系統(tǒng)開銷。

      4. 重量級(jí)鎖 (Heavyweight Lock)

      升級(jí)時(shí)機(jī):當(dāng)輕量級(jí)鎖的自旋失敗(例如,超過自旋次數(shù)或有其他線程也在自旋),鎖就會(huì)膨脹(Inflate)為重量級(jí)鎖。
      核心機(jī)制:
      鎖依賴于操作系統(tǒng)底層的 Mutex Lock(互斥量) 來實(shí)現(xiàn)。
      未能獲取鎖的線程不再自旋,而是會(huì)被掛起(BLOCKED),并進(jìn)入一個(gè)等待隊(duì)列。
      等待持有鎖的線程釋放鎖后,再由操作系統(tǒng)喚醒其中一個(gè)等待的線程。
      目標(biāo)場景:適用于高并發(fā)、高競爭的場景。雖然上下文切換(用戶態(tài) ? 內(nèi)核態(tài))開銷巨大,但它能保證在激烈競爭下,所有線程都能有序地獲取鎖。

      總結(jié)

      鎖狀態(tài) 核心機(jī)制 適用場景 開銷
      無鎖 - 無線程競爭
      偏向鎖 CAS 記錄線程 ID,后續(xù)僅檢查 單線程訪問 極低
      輕量級(jí)鎖 CAS + 自適應(yīng)自旋 線程交替執(zhí)行,競爭不激烈 CPU 自旋開銷
      重量級(jí)鎖 操作系統(tǒng) Mutex,線程掛起/喚醒 高并發(fā),競爭激烈 重量級(jí),涉及內(nèi)核態(tài)切換

      Synchronized

      synchronized 通過這套精巧的鎖升級(jí)機(jī)制,在性能和線程安全之間取得了完美的平衡。它不再是那個(gè)“笨重”的鎖,而是一個(gè)能夠根據(jù)競爭情況自動(dòng)調(diào)整策略的智能鎖。

      揭秘 Synchronized 的可重入性:它是如何實(shí)現(xiàn)的?

      synchronized 的可重入性(Reentrancy)是其核心特性之一,它保證了同一個(gè)線程可以多次獲取自己已經(jīng)持有的鎖,從而避免了自己把自己鎖死(死鎖)的情況。

      1. 什么是可重入性?為什么它很重要?

      想象以下場景:一個(gè)類中有兩個(gè) synchronized 方法,其中一個(gè)方法調(diào)用了另一個(gè)。

      public class ReentrantExample {
          
          public synchronized void methodA() {
              System.out.println("Executing methodA...");
              methodB(); // 調(diào)用另一個(gè)同步方法
          }
          
          public synchronized void methodB() {
              System.out.println("Executing methodB...");
          }
      }
      

      如果沒有可重入性,當(dāng)一個(gè)線程執(zhí)行 methodA() 時(shí),它獲取了對(duì)象的鎖。接著,它嘗試調(diào)用 methodB(),此時(shí)它需要再次獲取同一個(gè)對(duì)象的鎖。由于鎖已經(jīng)被自己持有,它會(huì)陷入無限等待,造成死鎖。

      可重入性解決了這個(gè)問題:它允許已經(jīng)持有鎖的線程,無需等待,直接再次獲取該鎖。

      2. Synchronized 如何在不同鎖狀態(tài)下保證可重入?

      synchronized 的可重入性設(shè)計(jì)貫穿了從偏向鎖到重量級(jí)鎖的整個(gè)升級(jí)過程,確保在任何狀態(tài)下行為一致。

      a) 偏向鎖階段 (Biased Lock)

      這是實(shí)現(xiàn)最簡單、開銷最小的階段。

      機(jī)制:線程進(jìn)入同步塊時(shí),只需檢查對(duì)象頭 Mark Word 中記錄的線程 ID 是否是自己。
      重入:如果是,直接進(jìn)入,無需任何額外操作。這就像進(jìn)自己家門,刷臉就行。

      b) 輕量級(jí)鎖階段 (Lightweight Lock)

      當(dāng)鎖升級(jí)為輕量級(jí)鎖后,機(jī)制變得復(fù)雜一些。

      機(jī)制:線程會(huì)在自己的棧幀中創(chuàng)建 Lock Record 來持有鎖。
      重入:當(dāng)線程嘗試重入時(shí),它會(huì)發(fā)現(xiàn)對(duì)象頭已經(jīng)指向一個(gè)位于自己棧幀的 Lock Record。此時(shí),JVM 會(huì)在當(dāng)前棧幀中再創(chuàng)建一個(gè) Lock Record,但將其內(nèi)部的 displaced_header 字段設(shè)為 null。這個(gè) null 標(biāo)記就代表了一次重入。退出同步塊時(shí),每遇到一個(gè) null 的 Lock Record,就代表完成一次重入解鎖。

      c) 重量級(jí)鎖階段 (Heavyweight Lock)

      這是最經(jīng)典、最廣為人知的實(shí)現(xiàn)方式。

      機(jī)制:鎖由底層的 ObjectMonitor 對(duì)象管理。
      重入:ObjectMonitor 內(nèi)部有一個(gè)名為 _recursions 或 _count 的計(jì)數(shù)器。當(dāng)一個(gè)線程獲取鎖后,計(jì)數(shù)器變?yōu)?1。該線程每重入一次,計(jì)數(shù)器就 +1。相應(yīng)地,每退出一個(gè)同步塊,計(jì)數(shù)器就 -1。直到計(jì)數(shù)器歸零,鎖才被真正釋放。

      3. 總結(jié)

      synchronized 的可重入性是其內(nèi)在基因,通過在不同鎖狀態(tài)下采用不同的策略(檢查線程ID、設(shè)置null標(biāo)記、維護(hù)計(jì)數(shù)器),無縫地保證了同一線程可以安全、高效地多次進(jìn)入同步代碼塊。

      這種精巧的設(shè)計(jì),使得開發(fā)者可以放心地在同步方法中調(diào)用其他同步方法,而不必?fù)?dān)心死鎖問題,極大地增強(qiáng)了 synchronized 關(guān)鍵字的健壯性和易用性。

      為什么說 Synchronized 是一個(gè)“不公平”的鎖?

      在面試或技術(shù)討論中,我們常聽到一個(gè)結(jié)論:synchronized 是一個(gè)非公平鎖(Non-fair Lock)。

      這個(gè)“不公平”聽起來像個(gè)缺點(diǎn),但實(shí)際上,它是 synchronized 為了性能而做出的一個(gè)精明權(quán)衡。本文將帶你徹底搞懂其中的緣由。

      1. 首先,什么是公平與非公平?

      讓我們用一個(gè)生活中的例子來理解:

      公平鎖 (Fair Lock):就像在銀行排隊(duì)辦業(yè)務(wù),講究“先來后到”。排在隊(duì)首的客戶(線程)一定比隊(duì)尾的客戶先得到服務(wù)。它保證了所有等待的線程最終都能獲得鎖,不會(huì)“餓死”。
      非公平鎖 (Non-fair Lock):不遵循嚴(yán)格的排隊(duì)規(guī)則。當(dāng)鎖被釋放時(shí),系統(tǒng)允許一個(gè)新來的、尚未排隊(duì)的線程去“插隊(duì)”,直接嘗試獲取鎖。如果它成功了,就跳過了所有正在排隊(duì)的線程。
      synchronized 就屬于后者。

      2. Synchronized 的“不公平”體現(xiàn)在哪里?

      synchronized 的非公平性貫穿于其鎖機(jī)制中,尤其在從輕量級(jí)鎖升級(jí)到重量級(jí)鎖的過程中表現(xiàn)得淋漓盡致。

      a) 輕量級(jí)鎖階段

      當(dāng)一個(gè)線程釋放輕量級(jí)鎖時(shí),其他正在自旋等待的線程會(huì)通過 CAS 競爭鎖。這個(gè)競爭本身就是“無序”的,誰的 CAS 操作先成功,誰就獲得鎖,沒有排隊(duì)的概念。

      b) 重量級(jí)鎖階段

      這是非公平性最核心的體現(xiàn)。當(dāng)鎖膨脹為重量級(jí)鎖后,所有獲取不到鎖的線程都會(huì)被掛起,放入一個(gè)等待隊(duì)列(_EntryList)中。

      當(dāng)持有鎖的線程釋放鎖時(shí),JVM 面臨一個(gè)選擇:

      • 公平的做法:從等待隊(duì)列的頭部喚醒一個(gè)線程,讓它獲取鎖。
      • 非公平的做法:允許一個(gè)剛剛進(jìn)入同步塊、尚未被掛起的新線程,直接嘗試獲取鎖。
        HotSpot 虛擬機(jī)synchronized** 選擇了后者**。 它會(huì)先讓新來的線程嘗試“搶”一下鎖,如果搶不到,這個(gè)新線程才會(huì)被掛起并加入等待隊(duì)列的隊(duì)尾。

      3. 為什么要設(shè)計(jì)成“不公平”?—— 性能!

      不公平的設(shè)計(jì)看似“不道德”,但它背后是極致的性能追求,核心目標(biāo)是提高系統(tǒng)的總吞吐量 (Throughput)。

      這主要是為了避免不必要的上下文切換 (Context Switch)。

      • 線程喚醒的成本:喚醒一個(gè)被掛起的線程成本非常高。它需要從內(nèi)核態(tài)切換回用戶態(tài),恢復(fù)線程的運(yùn)行環(huán)境,這比一個(gè)正在運(yùn)行的線程執(zhí)行幾百條指令還要慢。
      • 非公平的優(yōu)勢(shì):如果一個(gè)新來的、正在 CPU 上運(yùn)行的線程能夠立即獲取鎖并完成任務(wù),就避免了“喚醒舊線程”和“掛起新線程”這兩次昂貴的上下文切換。雖然對(duì)排隊(duì)的線程不公平,但從整個(gè)系統(tǒng)的角度看,減少了兩次線程狀態(tài)轉(zhuǎn)換,總的執(zhí)行效率更高。
        簡單來說,系統(tǒng)認(rèn)為,讓一個(gè)“熱乎”的(正在運(yùn)行的)線程直接干活,比費(fèi)勁去叫醒一個(gè)“睡著”的(被掛起)線程,成本要低得多。

      4. 非公平的代價(jià):線程餓死 (Starvation)

      非公平鎖的潛在風(fēng)險(xiǎn)是線程餓死。理論上,如果運(yùn)氣極差,一個(gè)排隊(duì)的線程可能會(huì)一直被新來的線程“插隊(duì)”,導(dǎo)致它永遠(yuǎn)也獲取不到鎖。

      不過,在實(shí)際應(yīng)用中,這種情況發(fā)生的概率極低。synchronized 的設(shè)計(jì)是在絕大多數(shù)場景下,用極小的“餓死”風(fēng)險(xiǎn)換取顯著的性能提升。

      5. 如果我需要公平鎖怎么辦?

      如果你有必須保證公平性的業(yè)務(wù)場景(例如,資源需要嚴(yán)格按申請(qǐng)順序分配),可以使用 java.util.concurrent.locks.ReentrantLock。

      它提供了一個(gè)構(gòu)造函數(shù)來讓你明確選擇:

      
      // 默認(rèn)構(gòu)造函數(shù),創(chuàng)建一個(gè)非公平鎖 (性能更高)
      Lock nonFairLock = new ReentrantLock();
      
      // 傳入 true,創(chuàng)建一個(gè)公平鎖 (保證順序,犧牲部分性能)
      Lock fairLock = new ReentrantLock(true); 
      

      總結(jié)

      synchronized 被設(shè)計(jì)為非公平鎖,并非一個(gè)缺陷,而是一種為性能優(yōu)化的策略。它通過允許新線程“插隊(duì)”,最大限度地減少了昂貴的線程上下文切換,從而提高了系統(tǒng)的整體吞吐量。

      這是一個(gè)經(jīng)典的性能與公平性之間的權(quán)衡 (Trade-off)。對(duì)于絕大多數(shù)應(yīng)用場景,synchronized 的這種“不公平”所帶來的性能優(yōu)勢(shì),遠(yuǎn)比其微乎其微的“餓死”風(fēng)險(xiǎn)更有價(jià)值。

      posted @ 2025-10-24 21:28  go__Ahead  閱讀(15)  評(píng)論(0)    收藏  舉報(bào)
      主站蜘蛛池模板: 日韩精品一区二区三区激情视频 | 三上悠亚精品一区二区久久| 中文字幕久久人妻熟人妻| 男人天堂亚洲天堂女人天堂| 99久久久国产精品免费无卡顿| 亚洲午夜精品久久久久久抢| 亚洲欧洲美洲在线观看| 日韩av一区二区三区在线| 马边| 国产午夜精品一区二区三| 亚洲精品成人区在线观看| 国产99视频精品免费视频36| 一区二区三区午夜无码视频| 亚洲中文精品久久久久久不卡| 国产一区二区高清不卡| 午夜射精日本三级| 超碰成人人人做人人爽| www国产亚洲精品久久网站| 亚洲一区av在线观看| 成人国产乱对白在线观看| 精品 无码 国产观看| 久久久久国产精品人妻| 亚洲国产精品成人av网| 亚洲一区中文字幕人妻| 97久久超碰亚洲视觉盛宴| 国产粉嫩美女一区二区三| 亚洲av片在线免费观看| 中文成人无字幕乱码精品区| 久久久久成人精品| 国产三级国产精品国产专| 人妻少妇精品视频专区| 国语精品自产拍在线观看网站| 一日本道伊人久久综合影| 亚洲有无码中文网| 亚洲精品美女一区二区| 亚洲精品喷潮一区二区三区| 国产一区二区三区不卡视频| 人妻丝袜无码专区视频网站| 国产成人无码AV大片大片在线观看| 日韩高清不卡免费一区二区| 本免费Av无码专区一区|