91欧美超碰AV自拍|国产成年人性爱视频免费看|亚洲 日韩 欧美一厂二区入|人人看人人爽人人操aV|丝袜美腿视频一区二区在线看|人人操人人爽人人爱|婷婷五月天超碰|97色色欧美亚州A√|另类A√无码精品一级av|欧美特级日韩特级

0
  • 聊天消息
  • 系統(tǒng)消息
  • 評(píng)論與回復(fù)
登錄后你可以
  • 下載海量資料
  • 學(xué)習(xí)在線課程
  • 觀看技術(shù)視頻
  • 寫(xiě)文章/發(fā)帖/加入社區(qū)
會(huì)員中心
創(chuàng)作中心

完善資料讓更多小伙伴認(rèn)識(shí)你,還能領(lǐng)取20積分哦,立即完善>

3天內(nèi)不再提示

面試必看:排隊(duì)自旋鎖之MCS鎖的實(shí)現(xiàn)原理與關(guān)鍵考點(diǎn)

jf_44130326 ? 來(lái)源:Linux1024 ? 2026-02-09 16:51 ? 次閱讀
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

在并發(fā)編程面試中,是繞不開(kāi)的核心話題,而自旋鎖作為輕量級(jí)鎖的代表,其優(yōu)化方案更是高頻考點(diǎn)。其中,MCS(以發(fā)明者John Mellor-CrummeyMichael Scott命名)作為排隊(duì)自旋鎖的經(jīng)典實(shí)現(xiàn),完美解決了傳統(tǒng)自旋鎖CPU資源浪費(fèi)”“緩存風(fēng)暴等痛點(diǎn),成為面試官評(píng)估候選人并發(fā)底層能力的重要標(biāo)尺。今天,我們就從面試視角拆解MCS鎖的實(shí)現(xiàn)邏輯,幫你輕松應(yīng)對(duì)相關(guān)提問(wèn)。

一、先搞懂:為什么需要MCS鎖?

在講MCS鎖之前,我們得先明確傳統(tǒng)自旋鎖的問(wèn)題”——這是面試中回答“MCS鎖設(shè)計(jì)初衷的關(guān)鍵切入點(diǎn)。

傳統(tǒng)自旋鎖(如基于CASTest-and-Set鎖)的核心問(wèn)題的是盲等:當(dāng)多個(gè)線程競(jìng)爭(zhēng)鎖時(shí),所有線程都會(huì)自旋等待同一個(gè)共享變量(如鎖狀態(tài)標(biāo)記),哪怕鎖已經(jīng)被釋放,也可能有大量線程無(wú)效自旋;更嚴(yán)重的是,多個(gè)線程頻繁讀取同一個(gè)變量會(huì)引發(fā)緩存一致性風(fēng)暴(多個(gè)CPU核心緩存同步該變量,導(dǎo)致性能損耗)。

MCS鎖的核心思想是排隊(duì)自旋:讓競(jìng)爭(zhēng)鎖的線程按順序排成一個(gè)單向鏈表,每個(gè)線程只自旋等待前一個(gè)線程釋放鎖的信號(hào),避免對(duì)同一個(gè)共享變量的集中競(jìng)爭(zhēng)。這種設(shè)計(jì)既減少了無(wú)效自旋,又消除了緩存風(fēng)暴,是高并發(fā)場(chǎng)景下的最優(yōu)自旋鎖方案之一。

二、MCS鎖的核心設(shè)計(jì):數(shù)據(jù)結(jié)構(gòu)+ 3個(gè)關(guān)鍵操作

面試中,“MCS鎖的實(shí)現(xiàn)通常需要你講清數(shù)據(jù)結(jié)構(gòu)定義**“加鎖、解鎖、自旋三個(gè)核心流程**。我們以Java為例(C/C++實(shí)現(xiàn)邏輯類似,只是語(yǔ)法差異),一步步拆解。

1.核心數(shù)據(jù)結(jié)構(gòu):線程節(jié)點(diǎn)(Node)與鎖狀態(tài)

MCS鎖的核心是用鏈表記錄等待線程,每個(gè)線程對(duì)應(yīng)一個(gè)Node節(jié)點(diǎn),節(jié)點(diǎn)中需包含兩個(gè)關(guān)鍵信息:

?isLocked:標(biāo)記當(dāng)前線程是否持有鎖(或是否需要自旋);

?next:指向鏈表中的下一個(gè)等待線程(形成排隊(duì)順序)。

同時(shí),鎖本身需要一個(gè)共享的尾指針tail,用于將新競(jìng)爭(zhēng)鎖的線程追加到鏈表尾部,這個(gè)尾指針通過(guò)CAS操作保證原子性。

Java中的簡(jiǎn)化定義如下(面試時(shí)寫(xiě)出這個(gè)結(jié)構(gòu),基本就成功了一半):

// 1. 線程節(jié)點(diǎn)類:記錄當(dāng)前線程的鎖狀態(tài)和下一個(gè)等待線程classNode{// 標(biāo)記是否需要自旋:true=需要等待,false=可獲取鎖volatilebooleanisLocked=true;// 指向鏈表中的下一個(gè)節(jié)點(diǎn)(下一個(gè)等待線程)volatileNodenext=null;}// 2. MCS鎖類:核心是共享的尾指針tailpublicclassMCSLock{// 共享尾指針:指向鏈表最后一個(gè)節(jié)點(diǎn),初始為nullprivatevolatileNodetail=null;// 每個(gè)線程獨(dú)有的節(jié)點(diǎn)(避免線程安全問(wèn)題,用ThreadLocal存儲(chǔ))privateThreadLocal currentNode = ThreadLocal.withInitial(Node::new);}

這里有個(gè)面試高頻細(xì)節(jié):為什么用ThreadLocal存儲(chǔ)當(dāng)前線程的Node?

答:因?yàn)槊總€(gè)線程只能操作自己的Node節(jié)點(diǎn)(修改isLocked)和前一個(gè)線程的Node節(jié)點(diǎn)(設(shè)置next),用ThreadLocal可以避免多個(gè)線程競(jìng)爭(zhēng)同一個(gè)Node,同時(shí)保證每個(gè)線程對(duì)應(yīng)唯一節(jié)點(diǎn)。

2.加鎖流程(lock ()):排隊(duì)入隊(duì),確定等待對(duì)象

加鎖的核心是將當(dāng)前線程追加到鏈表尾部,并找到前一個(gè)線程,具體分4步(面試時(shí)建議結(jié)合步驟+代碼+流程圖講解):

加鎖流程流程圖

wKgZO2kah4aACuM_AAOFIAmI9TM072.png

步驟1:獲取當(dāng)前線程的Node節(jié)點(diǎn)

通過(guò)ThreadLocal拿到當(dāng)前線程獨(dú)有的Node,確保線程安全。

步驟2CAS嘗試將當(dāng)前節(jié)點(diǎn)設(shè)為新的tail

CAS操作(compareAndSet)將tail舊值更新為當(dāng)前節(jié)點(diǎn)

?如果CAS成功:說(shuō)明當(dāng)前線程是第一個(gè)競(jìng)爭(zhēng)鎖的線程(鏈表為空),直接獲取鎖,無(wú)需自旋;

?如果CAS失?。赫f(shuō)明已有其他線程在排隊(duì),當(dāng)前線程需要加入鏈表尾部。

步驟3:找到前一個(gè)線程的Nodeprev

CAS失敗后,舊的tail就是前一個(gè)線程的節(jié)點(diǎn)(prev,需要將prevnext指向當(dāng)前節(jié)點(diǎn)(把當(dāng)前線程接入鏈表)。

步驟4:自旋等待前一個(gè)線程釋放鎖

當(dāng)前線程自旋等待prev.isLocked變?yōu)?/span>false(前一個(gè)線程釋放鎖的信號(hào)),直到條件滿足后,才能獲取鎖。

加鎖的Java實(shí)現(xiàn)代碼如下(面試時(shí)寫(xiě)出關(guān)鍵邏輯即可):

publicvoidlock(){// 步驟1:獲取當(dāng)前線程的Node節(jié)點(diǎn)NodecurrNode=currentNode.get();// 步驟2:CAS嘗試將當(dāng)前節(jié)點(diǎn)設(shè)為新tail(入隊(duì))NodeprevNode=CASUpdateTail(null, currNode) ?null: tail;// 步驟3:如果有前一個(gè)線程(prevNode不為null),則將當(dāng)前節(jié)點(diǎn)接入鏈表if(prevNode !=null) {  // 將前一個(gè)節(jié)點(diǎn)的next指向當(dāng)前節(jié)點(diǎn)(當(dāng)前線程排隊(duì)到prev后面)   prevNode.next = currNode;  // 步驟4:自旋等待前一個(gè)線程釋放鎖(直到prev.isLocked為false)  while(currNode.isLocked) {    // 自旋:可加Thread.yield()減少CPU占用(面試可提優(yōu)化點(diǎn))     Thread.yield();   } }// 如果prevNode為null(CAS成功),直接獲取鎖,無(wú)需自旋}// 輔助方法:CAS更新tail指針(簡(jiǎn)化版,實(shí)際需用Unsafe類或AtomicReference)privatebooleanCASUpdateTail(Node expect, Node update){if(tail == expect) {   tail = update;  returntrue; }returnfalse;}

3.解鎖流程(unlock ()):?jiǎn)拘严乱粋€(gè)線程,出隊(duì)

解鎖的核心是找到下一個(gè)等待線程,通知它可以獲取鎖,避免鏈表中后續(xù)線程一直自旋,具體分3步(面試時(shí)建議結(jié)合步驟+代碼+流程圖講解):

解鎖流程流程圖

wKgZO2kah4eAIsOGAANqqE24HDo582.png

步驟1:獲取當(dāng)前線程的Node節(jié)點(diǎn)

同樣通過(guò)ThreadLocal獲取,當(dāng)前節(jié)點(diǎn)持有鎖,解鎖時(shí)需操作它。

步驟2:檢查是否有下一個(gè)等待線程(next

?如果next == null:說(shuō)明當(dāng)前線程是鏈表最后一個(gè)節(jié)點(diǎn),需要嘗試將tail設(shè)為null(避免后續(xù)線程入隊(duì)時(shí)找不到prev);

?如果next != null:說(shuō)明有線程在排隊(duì),需要將next.isLocked設(shè)為false(通知下一個(gè)線程可以獲取鎖)。

步驟3:清理當(dāng)前線程的Node(可選)

避免ThreadLocal內(nèi)存泄漏,可在解鎖后移除當(dāng)前節(jié)點(diǎn)。

解鎖的Java實(shí)現(xiàn)代碼如下:

publicvoidunlock(){// 步驟1:獲取當(dāng)前線程的Node節(jié)點(diǎn) Node currNode = currentNode.get();// 步驟2:檢查是否有下一個(gè)等待線程if(currNode.next ==null) {  // 情況1:沒(méi)有下一個(gè)線程,嘗試將tail設(shè)為null  if(CASUpdateTail(currNode,null)) {    // CAS成功:直接返回(鏈表已空)    return;   }  // CAS失敗:說(shuō)明有新線程正在入隊(duì),需要等待它設(shè)置next  while(currNode.next ==null) {     Thread.yield();   } }// 情況2:有下一個(gè)線程,通知它可以獲取鎖(設(shè)置next.isLocked為false) currNode.next.isLocked =false;// 步驟3:清理當(dāng)前節(jié)點(diǎn)(避免ThreadLocal內(nèi)存泄漏) currNode.next =null; currentNode.remove();}

這里有個(gè)面試易錯(cuò)點(diǎn):為什么CAS更新tail失敗后要循環(huán)等待next?

答:因?yàn)楫?dāng)當(dāng)前線程(最后一個(gè)節(jié)點(diǎn))解鎖時(shí),可能有新線程正在執(zhí)行lock()的步驟3(設(shè)置prev.next = currNode),此時(shí)currNode.next還未被賦值,直接解鎖會(huì)導(dǎo)致新線程永遠(yuǎn)自旋。因此需要循環(huán)等待,直到新線程的next設(shè)置完成,再通知它獲取鎖。

三、面試高頻問(wèn)題:MCS鎖的優(yōu)勢(shì)與考點(diǎn)

掌握了實(shí)現(xiàn)邏輯后,還需要能回答“MCS鎖的核心優(yōu)勢(shì)”“與其他鎖的區(qū)別等問(wèn)題,這些是面試中的加分項(xiàng)。

1. MCS鎖的核心優(yōu)勢(shì)(必答)

?無(wú)緩存風(fēng)暴:每個(gè)線程只自旋等待前一個(gè)節(jié)點(diǎn)的isLocked”,而不是同一個(gè)共享變量,減少CPU緩存同步開(kāi)銷;

?公平性:線程按入隊(duì)順序獲取鎖,避免饑餓(傳統(tǒng)自旋鎖可能導(dǎo)致線程一直搶不到鎖);

?低無(wú)效自旋:只有前一個(gè)線程釋放鎖時(shí),下一個(gè)線程才會(huì)停止自旋,減少無(wú)效CPU占用。

2. MCS鎖與CLH鎖的區(qū)別(高頻對(duì)比題)

CLH鎖(另一種排隊(duì)自旋鎖)與MCS鎖原理類似,但有一個(gè)關(guān)鍵差異:

?自旋對(duì)象不同MCS鎖自旋當(dāng)前節(jié)點(diǎn)的isLocked”CLH鎖自旋前一個(gè)節(jié)點(diǎn)的isLocked”;

?適用場(chǎng)景不同MCS鎖更適合非緩存友好的環(huán)境(如分布式鎖),CLH鎖在共享內(nèi)存環(huán)境(如單機(jī)器多線程)中緩存效率更高,但MCS鎖的實(shí)現(xiàn)更直觀,面試中更??肌?/span>

3.實(shí)際應(yīng)用:JDK中有MCS鎖嗎?

答:JDK 1.6之后,ReentrantLock的非公平鎖實(shí)現(xiàn)中,底層的AQSAbstractQueuedSynchronizer)隊(duì)列其實(shí)借鑒了MCS鎖的排隊(duì)思想”——AQSNode節(jié)點(diǎn)、tail指針、CAS入隊(duì)等邏輯,本質(zhì)上是MCS鎖的變種(但AQS是阻塞鎖,不是自旋鎖)。面試時(shí)提到這一點(diǎn),能體現(xiàn)你對(duì)JDK源碼的理解。

四、總結(jié):MCS鎖面試答題框架

最后,給大家整理一個(gè)“MCS鎖面試答題框架,按這個(gè)邏輯說(shuō),既清晰又全面:

1.定義MCS鎖是排隊(duì)自旋鎖的實(shí)現(xiàn),通過(guò)鏈表記錄等待線程,每個(gè)線程只自旋前一個(gè)線程的釋放信號(hào);

2.設(shè)計(jì)初衷:解決傳統(tǒng)自旋鎖的盲等緩存風(fēng)暴問(wèn)題;

3.核心結(jié)構(gòu)Node節(jié)點(diǎn)(isLockednext+共享tail指針+ ThreadLocal存儲(chǔ)當(dāng)前節(jié)點(diǎn);

4.流程

?加鎖:獲取節(jié)點(diǎn)→CAS入隊(duì)接入鏈表自旋等待前節(jié)點(diǎn);

?解鎖:獲取節(jié)點(diǎn)檢查next→通知next解鎖清理節(jié)點(diǎn);

1.優(yōu)勢(shì):無(wú)緩存風(fēng)暴、公平、低無(wú)效自旋;

2.延伸:與CLH鎖的區(qū)別、JDKAQS的借鑒。

掌握這個(gè)框架,再結(jié)合代碼示例和流程圖,MCS鎖相關(guān)的面試題就能輕松應(yīng)對(duì)了。

聲明:本文內(nèi)容及配圖由入駐作者撰寫(xiě)或者入駐合作網(wǎng)站授權(quán)轉(zhuǎn)載。文章觀點(diǎn)僅代表作者本人,不代表電子發(fā)燒友網(wǎng)立場(chǎng)。文章及其配圖僅供工程師學(xué)習(xí)之用,如有內(nèi)容侵權(quán)或者其他違規(guī)問(wèn)題,請(qǐng)聯(lián)系本站處理。 舉報(bào)投訴
  • cpu
    cpu
    +關(guān)注

    關(guān)注

    68

    文章

    11275

    瀏覽量

    224914
  • 線程
    +關(guān)注

    關(guān)注

    0

    文章

    509

    瀏覽量

    20824
  • 自旋鎖
    +關(guān)注

    關(guān)注

    0

    文章

    14

    瀏覽量

    1794
收藏 人收藏
加入交流群
微信小助手二維碼

掃碼添加小助手

加入工程師交流群

    評(píng)論

    相關(guān)推薦
    熱點(diǎn)推薦

    深度解析自旋自旋實(shí)現(xiàn)方案

    入場(chǎng)券自旋MCS自旋都屬于排隊(duì)自旋
    發(fā)表于 09-19 11:39 ?5047次閱讀
    深度解析<b class='flag-5'>自旋</b><b class='flag-5'>鎖</b>及<b class='flag-5'>自旋</b><b class='flag-5'>鎖</b>的<b class='flag-5'>實(shí)現(xiàn)</b>方案

    面試必看:java面試考點(diǎn)精講視頻教程

    面試必看:java面試考點(diǎn)精講視頻教程 Java作為目前比較火的計(jì)算機(jī)語(yǔ)言之一,連續(xù)幾年蟬聯(lián)最受程序員歡迎的計(jì)算機(jī)語(yǔ)言榜首,因此每年新入職Java程序員也數(shù)不勝數(shù)。很多java程序員在學(xué)成之后,會(huì)面
    發(fā)表于 07-06 12:46

    信號(hào)量、互斥自旋

    信號(hào)量、互斥自旋http://bbs.edu118.com/forum.php?mod=viewthread&tid=488&fromuid=231(出處: 信盈達(dá)IT技術(shù)社
    發(fā)表于 08-29 09:48

    Linux內(nèi)核同步機(jī)制的自旋原理是什么?

    自旋是專為防止多處理器并發(fā)而引入的一種,它在內(nèi)核中大量應(yīng)用于中斷處理等部分(對(duì)于單處理器來(lái)說(shuō),防止中斷處理中的并發(fā)可簡(jiǎn)單采用關(guān)閉中斷的方式,即在標(biāo)志寄存器中關(guān)閉/打開(kāi)中斷標(biāo)志位,不需要自旋
    發(fā)表于 03-31 08:06

    怎么在atmega128中實(shí)現(xiàn)自旋?

    什么是自旋?有哪些缺陷?怎么在atmega128中實(shí)現(xiàn)自旋?
    發(fā)表于 01-24 06:54

    信號(hào)量和自旋

    。??? Linux 使用的同步機(jī)制可以說(shuō)從2.0到2.6以來(lái)不斷發(fā)展完善。從最初的原子操作,到后來(lái)的信號(hào)量,從大內(nèi)核到今天的自旋。這些同步機(jī)制的發(fā)展伴隨 Linux從單處理器到對(duì)稱多處理器的過(guò)度
    發(fā)表于 04-02 14:43 ?1080次閱讀

    Linux 自旋spinlock

    ,所以同一時(shí)刻只能有一個(gè)任務(wù)獲取到。 內(nèi)核當(dāng)發(fā)生訪問(wèn)資源沖突的時(shí)候,通常有兩種處理方式: 一個(gè)是原地等待 一個(gè)是掛起當(dāng)前進(jìn)程,調(diào)度其他進(jìn)程執(zhí)行(睡眠) 自旋 Spinlock 是內(nèi)核中提供的一種比較常見(jiàn)的
    的頭像 發(fā)表于 09-11 14:36 ?2656次閱讀

    自旋的發(fā)展歷史與使用方法

    自旋是Linux內(nèi)核里最常用的之一,自旋的概念很簡(jiǎn)單,就是如果加鎖失敗在等時(shí)是使用休眠等
    的頭像 發(fā)表于 08-08 08:51 ?2565次閱讀

    使用Linux自旋實(shí)現(xiàn)互斥點(diǎn)燈

    自旋最多只能被一個(gè)可執(zhí)行線程持有。如果一個(gè)線程試圖獲得一個(gè)已經(jīng)被持有的自旋,那么該線程將循環(huán)等待,然后不斷的判斷是否能夠被成功獲取,直
    的頭像 發(fā)表于 04-13 15:09 ?1384次閱讀
    使用Linux<b class='flag-5'>自旋</b><b class='flag-5'>鎖</b><b class='flag-5'>實(shí)現(xiàn)</b>互斥點(diǎn)燈

    自旋和互斥的區(qū)別有哪些

    自旋 自旋與互斥很相似,在訪問(wèn)共享資源之前對(duì)自旋
    的頭像 發(fā)表于 07-21 11:19 ?1.1w次閱讀

    如何用C++11實(shí)現(xiàn)自旋

    下面我會(huì)分析一下自旋,并代碼實(shí)現(xiàn)自旋和互斥的性能對(duì)比,以及利用C++11
    的頭像 發(fā)表于 11-11 16:48 ?2461次閱讀
    如何用C++11<b class='flag-5'>實(shí)現(xiàn)</b><b class='flag-5'>自旋</b><b class='flag-5'>鎖</b>

    互斥自旋的區(qū)別 自旋臨界區(qū)可以被中斷嗎?

    互斥自旋的區(qū)別 自旋臨界區(qū)可以被中斷嗎? 互斥
    的頭像 發(fā)表于 11-22 17:41 ?1645次閱讀

    自旋和互斥的使用場(chǎng)景是什么

    自旋和互斥是兩種常見(jiàn)的同步機(jī)制,它們?cè)诙嗑€程編程中被廣泛使用。在本文中,我們將介紹自旋和互斥
    的頭像 發(fā)表于 07-10 10:05 ?2206次閱讀

    互斥自旋實(shí)現(xiàn)原理

    互斥自旋是操作系統(tǒng)中常用的同步機(jī)制,用于控制對(duì)共享資源的訪問(wèn),以避免多個(gè)線程或進(jìn)程同時(shí)訪問(wèn)同一資源,從而引發(fā)數(shù)據(jù)不一致或競(jìng)爭(zhēng)條件等問(wèn)題。 互斥(Mutex) 互斥
    的頭像 發(fā)表于 07-10 10:07 ?1644次閱讀

    面試必看!排隊(duì)自旋32位變量的域劃分與核心作用

    在操作系統(tǒng)面試中,并發(fā)同步機(jī)制一直是高頻考點(diǎn),而排隊(duì)自旋作為解決傳統(tǒng)自旋
    的頭像 發(fā)表于 02-09 16:54 ?802次閱讀
    <b class='flag-5'>面試</b><b class='flag-5'>必看</b>!<b class='flag-5'>排隊(duì)</b><b class='flag-5'>自旋</b><b class='flag-5'>鎖</b>32位變量的域劃分與核心作用