内射老阿姨1区2区3区4区_久久精品人人做人人爽电影蜜月_久久国产精品亚洲77777_99精品又大又爽又粗少妇毛片

Java中自旋鎖的作用有哪些-創(chuàng)新互聯(lián)

這篇文章將為大家詳細(xì)講解有關(guān)Java中自旋鎖的作用有哪些,文章內(nèi)容質(zhì)量較高,因此小編分享給大家做個(gè)參考,希望大家閱讀完這篇文章后對(duì)相關(guān)知識(shí)有一定的了解。

在鐘山等地區(qū),都構(gòu)建了全面的區(qū)域性戰(zhàn)略布局,加強(qiáng)發(fā)展的系統(tǒng)性、市場(chǎng)前瞻性、產(chǎn)品創(chuàng)新能力,以專注、極致的服務(wù)理念,為客戶提供成都網(wǎng)站設(shè)計(jì)、網(wǎng)站建設(shè)、外貿(mào)網(wǎng)站建設(shè) 網(wǎng)站設(shè)計(jì)制作按需開(kāi)發(fā)網(wǎng)站,公司網(wǎng)站建設(shè),企業(yè)網(wǎng)站建設(shè),成都品牌網(wǎng)站建設(shè),成都全網(wǎng)營(yíng)銷,成都外貿(mào)網(wǎng)站建設(shè)公司,鐘山網(wǎng)站建設(shè)費(fèi)用合理。

鎖的優(yōu)化:自旋鎖

當(dāng)多個(gè)線程想同時(shí)訪問(wèn)同一個(gè)資源時(shí),就存在資源沖突,這時(shí),大家最直接想到的就是加鎖來(lái)互斥訪問(wèn),加鎖會(huì)有這么幾個(gè)問(wèn)題:

  1. 等待資源的線程進(jìn)入睡眠,發(fā)生用戶態(tài)向內(nèi)核態(tài)的切換,有一定的性能開(kāi)銷;

  2. 占用資源的線程很快就用完并釋放,這時(shí)等待的線程被喚醒,又要立即切換回用戶態(tài);


那么,如果有一種方式,使得等待的線程先短暫的等待一會(huì)兒,有可能有兩種結(jié)果:

  1. 等待的時(shí)間超過(guò)了這一會(huì)兒,那沒(méi)辦法,只好進(jìn)入睡眠;

  2. 等待的時(shí)間還未超過(guò),占用資源的線程釋放了,這時(shí)等待的線程就可以直接占用資源。


這就是鎖的小優(yōu)化:自旋鎖! 自旋鎖并不是真正的鎖,而是讓等待的線程先原地"小轉(zhuǎn)"一下,小轉(zhuǎn)一下,通常小轉(zhuǎn)一下的實(shí)現(xiàn)方式很簡(jiǎn)單:

int SPIN_LOCK_NUM = 64;
int i = 0;
boolean wait = true;

do {
 wait = // 嘗試獲取資源鎖
} while (wait && (++i) < SPIN_LOCK_NUM);

我們通過(guò)循環(huán)一定的次數(shù)來(lái)自旋。 \color{red}{但是我們也應(yīng)該知道,不進(jìn)入休眠而原地打轉(zhuǎn),是會(huì)一直消耗 CPU 資源的,因此,才有了自旋限制!}但是我們也應(yīng)該知道,不進(jìn)入休眠而原地打轉(zhuǎn),是會(huì)一直消耗CPU資源的,因此,才有了自旋限制!

看下面的JDK源碼:

public final class Unsafe {
 public final int getAndSetInt(Object var1, long var2, int var4) {
  int var5;
  do {
   var5 = this.getIntVolatile(var1, var2);
  } while(!this.compareAndSwapInt(var1, var2, var5, var4));
 
  return var5;
 }
}

我們可以看到,CAS就是采用的自旋鎖方式,持續(xù)的嘗試讀取新的 volatile 修飾的變量的值,并嘗試去用期望的值去比較,然后更新。

不過(guò)這里我們要注意,因?yàn)槭菬o(wú)限循環(huán),因此我們要保證占用資源的線程很快就能釋放,而不是長(zhǎng)時(shí)間占用(當(dāng)然,因?yàn)檫@里的源碼系統(tǒng)也設(shè)定了 int 型變量,因此,占用該變量的線程很快就會(huì)使用完而釋放)。

三、自旋鎖的死鎖

啥?怎么會(huì)有死鎖? 自旋鎖雖然好用,若我們只是停留在上面的分析,那么還是很膚淺的;雖然自旋鎖有很大的優(yōu)勢(shì),但同樣缺點(diǎn)也不少,除了上面說(shuō)的,原地打轉(zhuǎn)(忙等待)會(huì)一直消耗CPU資源,同時(shí),還會(huì)有一個(gè)潛在的可能缺陷:死鎖。

3.1、系統(tǒng)中斷

在聊死鎖之前,我們需要先了解一下系統(tǒng)中斷事件(大學(xué)課本里有這一章節(jié),ASM匯編中也涉及到系統(tǒng)中斷向量表):

中斷是指,CPU正常運(yùn)行期間,由于有內(nèi)/外部事件,或者由程序預(yù)先安排的事件,引起CPU暫停當(dāng)前工作,轉(zhuǎn)而去處理該事件,當(dāng)處理完該事件后再返回繼續(xù)運(yùn)行被中斷(暫停)的程序。通常,操作系統(tǒng)將中斷分為兩類:外部中斷(硬件中斷)和內(nèi)部中斷(異常中斷,即軟件引起的);

例如:由IO設(shè)備引起的中斷為硬件中斷,比如,鍵盤(pán)輸入,硬盤(pán)/光驅(qū)讀寫(xiě)等;異常中斷很好理解,比如 NullPointerException 等。

3.2、中斷處理程序

系統(tǒng)提供了一個(gè)API使得我們的程序能夠向系統(tǒng)申請(qǐng)注冊(cè)一個(gè)中斷處理程序(例如:程序接收用戶的輸入事件)。

request_irq(unsigned int irq, irq_handler_t handler, unsigned long flags, const char *name, void *dev)

參數(shù)含義如下:

  • irq: 中斷號(hào),系統(tǒng)定義好,具體可查看中斷向量表;

  • handler: 中斷后發(fā)生的ISR(Interrupt Service Routines),直接翻譯為:中斷服務(wù)路由;實(shí)際類似,是響應(yīng)中斷服務(wù)的程序;

  • flags: 中斷標(biāo)志;

  • name: 中斷相關(guān)的設(shè)備的ASCII,如:"keyboard",這些名字會(huì)在 /proc/irq 和 /proc/interrupts 中使用;

  • dev: 用于共享中斷線,傳遞驅(qū)動(dòng)程序的設(shè)備結(jié)構(gòu)。非共享類型的中斷,直接設(shè)置成為 NULL


中斷標(biāo)志(flags):

  • IRQF_DISABLED: 內(nèi)核處理該ISR期間,禁止其它中斷(一般很少使用);

  • IRQF_SAMPLE_RANDOM: 表明該設(shè)備產(chǎn)生的中斷對(duì)內(nèi)核熵池有貢獻(xiàn);

  • IRQF_TIMER: 系統(tǒng)定時(shí)器;

  • IRQF_SHARED: 多個(gè)ISR共享中斷線,即一個(gè)中斷,可存在多個(gè)ISR;


調(diào)用 request_irq 成功時(shí)返回0,常見(jiàn)錯(cuò)誤是 -EBUSY,表示給定的中斷線已經(jīng)在使用(沒(méi)有指定IRQF_SHARED)。

注:

  1. 該函數(shù)可能引起睡眠,所以不允許在中斷上下文或者不允許睡眠的程序中使用!

  2. Linux 中的中斷處理程序是無(wú)須重入的。當(dāng)給定的中斷處理程序正在執(zhí)行的時(shí)候,其中斷線在所有的處理器上都會(huì)被屏蔽掉,以防在同一個(gè)中斷線上又接收到另一個(gè)新的中斷。通常情況下,除了該中斷的其他中斷都是打開(kāi)的,也就是說(shuō)其他的中斷線上的重點(diǎn)都能夠被處理,但是當(dāng)前的中斷線總是被禁止的,故,同一個(gè)中斷處理程序是絕對(duì)不會(huì)被自己嵌套的。


那這和死鎖有何關(guān)系呢?額,下一小節(jié)會(huì)談到。但這里之所有提到中斷,是因?yàn)槲覀冞€要知道一件事,當(dāng)系統(tǒng)產(chǎn)生中斷,程序被暫停時(shí),程序是不能進(jìn)入休眠的,此時(shí)程序只能采用一種方式:自旋,來(lái)保證不會(huì)睡眠。

為何不能睡眠?這里就涉及到『中斷上下文 context』!

3.3、中斷上下文 Context

上面說(shuō)了,request_irq 可能引起睡眠,所以不允許在中斷上下文中使用,也就是說(shuō),中斷上下文不允許睡眠!

中斷上下文:它與進(jìn)程上下文不一樣,中斷上下文是內(nèi)核正在執(zhí)行ISR。ISR沒(méi)有自己獨(dú)立的棧,而是使用內(nèi)核棧,大小一般是有限制的(32位是8KB大?。M瑫r(shí),ISR是打斷了正常的程序流程,因此必須保證ISR執(zhí)行速度快。正因?yàn)橐獔?zhí)行速度快,所以,中斷上下文不允許睡眠,且不允許被阻塞!

大家可能會(huì)說(shuō)了,執(zhí)行速度快不允許睡眠,這解釋不合理,我睡眠個(gè)1ms不行么?嗯,下面我們就來(lái)分析下不能睡眠的真正原因:

1.中斷處理時(shí),不會(huì)發(fā)生進(jìn)程切換。

  • 因?yàn)槟艽驍喈?dāng)前中斷的只可能是更高優(yōu)先級(jí)的中斷,其它進(jìn)程的優(yōu)先級(jí)是不會(huì)比中斷優(yōu)先級(jí)更高的;

  • 如果中斷上下文休眠,則沒(méi)有辦法喚醒它,因?yàn)樗械?wake_up_xxx 是針對(duì)進(jìn)程而言,而中斷沒(méi)有進(jìn)程的概念;

  • 只要是中斷(硬中or軟中,不是香煙),都發(fā)生在內(nèi)核,如果中斷上下文睡眠了,內(nèi)核就阻塞了,系統(tǒng)能阻塞么?不能!阻塞了你就只能重啟機(jī)器了;

2.schedule 在切換進(jìn)程時(shí),會(huì)保存當(dāng)前的進(jìn)程上下文(CPU寄存器的值、狀態(tài)、堆棧SP內(nèi)容)以便以后恢復(fù)再運(yùn)行。中斷發(fā)生后,內(nèi)核會(huì)保存當(dāng)前被中斷進(jìn)程的上下文。在ISR中,是中斷上下文,如果休眠或阻塞,則會(huì)調(diào)用 schedule,保存的進(jìn)程上下文不是當(dāng)前進(jìn)程的上下文,所以不能在ISR中調(diào)用 schedule;
3.內(nèi)核中 schedule 在進(jìn)入時(shí)會(huì)判斷是否處于中斷上下文:

if(unlikely(in_interrupt()))) ..... crash!!!

4.中斷 handler 會(huì)使用被中斷的進(jìn)程內(nèi)核堆棧,但不會(huì)對(duì)其有任何影響,因?yàn)?handler用之前會(huì)保存,用完后會(huì)清除并恢復(fù)原貌;
5.處理中斷上下文中,內(nèi)核是不可搶占的,如果休眠,則內(nèi)核....一定會(huì)被掛起,同樣,你只能重啟機(jī)器了;
所以,被中斷的程序也不能睡眠!那么只能使用『自旋鎖』來(lái)原地打轉(zhuǎn)。

那還是沒(méi)有說(shuō)自旋為何會(huì)死鎖?

自旋鎖是不能遞歸,否則自己等待自己已經(jīng)獲取的鎖,將會(huì)導(dǎo)致死鎖!

一個(gè)線程獲取了一個(gè)自旋鎖,在執(zhí)行這程中被中斷處理程序打斷,因此該線程只是暫停執(zhí)行,并未退出,仍持有自旋鎖;而中斷處理程序嘗試獲取自旋鎖而獲取不到,只能自旋;這就造成一個(gè)事實(shí):ISR拿不到自旋鎖,導(dǎo)致自旋而無(wú)法退出,該線程被中斷無(wú)法恢復(fù)執(zhí)行至退出釋放自旋鎖,此時(shí)就造成了死鎖,導(dǎo)致系統(tǒng)崩潰。

四、死鎖解決

發(fā)生自旋鎖死鎖,往往因?yàn)閱蜟PU這個(gè)臨界資源發(fā)生了搶占,使得一方持有自旋鎖被中斷暫停,一方不斷自旋來(lái)嘗試獲取自旋鎖。因此,在多CPU架構(gòu)下,兩方如果分別運(yùn)行在不同CPU上,是不會(huì)發(fā)生死鎖的。

因此,自旋鎖有幾個(gè)重要特性需要掌握(精髓):

  • 持有自旋鎖的線程(此時(shí)肯定在臨界區(qū))不能休眠,休眠會(huì)引起進(jìn)程切換,CPU就會(huì)被另一個(gè)進(jìn)程占用等無(wú)法使用;

  • 持有自旋鎖的線程不允許被中斷,哪怕是ISR也不行,否則就存在ISR自旋;

  • 持有自旋鎖的線程,其內(nèi)核不能被搶占,否則等同于CPU被搶占;


所以,根據(jù)以上總結(jié)一點(diǎn):持有自旋鎖的線程,不能因?yàn)槿魏卧蚨艞塁PU! 也因此基于上述問(wèn)題,自旋也需要添加一個(gè)上限時(shí)間以防死鎖。

linux上的自旋鎖有三種實(shí)現(xiàn):

  1. 在單cpu,不可搶占內(nèi)核中,自旋鎖為空操作。

  2. 在單cpu,可搶占內(nèi)核中,自旋鎖實(shí)現(xiàn)為“禁止內(nèi)核搶占”,并不實(shí)現(xiàn)“自旋”。(注意)

  3. 在多cpu,可搶占內(nèi)核中,自旋鎖實(shí)現(xiàn)為“禁止內(nèi)核搶占” + “自旋”。

關(guān)于Java中自旋鎖的作用有哪些就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,可以學(xué)到更多知識(shí)。如果覺(jué)得文章不錯(cuò),可以把它分享出去讓更多的人看到。

網(wǎng)頁(yè)標(biāo)題:Java中自旋鎖的作用有哪些-創(chuàng)新互聯(lián)
地址分享:http://www.rwnh.cn/article16/joigg.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供軟件開(kāi)發(fā)、企業(yè)建站、電子商務(wù)、外貿(mào)建站定制開(kāi)發(fā)、網(wǎng)站設(shè)計(jì)

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來(lái)源: 創(chuàng)新互聯(lián)

外貿(mào)網(wǎng)站建設(shè)
五寨县| 临沂市| 平邑县| 四川省| 剑河县| 山丹县| 吉林市| 西华县| 宣武区| 鄂托克前旗| 鄱阳县| 京山县| 商城县| 乳山市| 万年县| 馆陶县| 迁西县| 桐乡市| 蛟河市| 桃江县| 梁河县| 墨脱县| 呼和浩特市| 大方县| 闽清县| 肥乡县| 穆棱市| 自治县| 临朐县| 文成县| 屯昌县| 瑞昌市| 安国市| 米易县| 铜山县| 金寨县| 得荣县| 中西区| 加查县| 扶风县| 方城县|