激情久久久_欧美视频区_成人av免费_不卡视频一二三区_欧美精品在欧美一区二区少妇_欧美一区二区三区的

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|JavaScript|易語言|

香港云服务器
服務器之家 - 編程語言 - Java教程 - Java 自旋鎖(spinlock)相關知識總結

Java 自旋鎖(spinlock)相關知識總結

2021-08-09 11:43小小青葉 Java教程

這篇文章主要介紹了Java 自旋鎖(spinlock)相關知識總結,幫助大家更好的理解和使用Java,感興趣的朋友可以了解下

一、前言

談到『自旋鎖』,可能大家會說,這有啥好講的,不就是等待資源的線程"原地打轉"嘛。嗯,字面理解的意思很到位,但能深入具體點嗎?自旋鎖的設計真就這么簡單?

本文或者說本系列的目的,都是讓大家不要停留在表面,而是深入分析,做到:

  • 靈活使用
  • 掌握原理
  • 優缺點

二、鎖的優化:自旋鎖

當多個線程想同時訪問同一個資源時,就存在資源沖突,這時,大家最直接想到的就是加鎖來互斥訪問,加鎖會有這么幾個問題:

  1. 等待資源的線程進入睡眠,發生用戶態向內核態的切換,有一定的性能開銷;
  2. 占用資源的線程很快就用完并釋放,這時等待的線程被喚醒,又要立即切換回用戶態;

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

  1. 等待的時間超過了這一會兒,那沒辦法,只好進入睡眠;
  2. 等待的時間還未超過,占用資源的線程釋放了,這時等待的線程就可以直接占用資源。

這就是鎖的小優化:自旋鎖! 自旋鎖并不是真正的鎖,而是讓等待的線程先原地"小轉"一下,小轉一下,通常小轉一下的實現方式很簡單:

?
1
2
3
4
5
6
7
int SPIN_LOCK_NUM = 64;
int i = 0;
boolean wait = true;
 
do {
 wait = // 嘗試獲取資源鎖
} while (wait && (++i) < SPIN_LOCK_NUM);

我們通過循環一定的次數來自旋。 \color{red}{但是我們也應該知道,不進入休眠而原地打轉,是會一直消耗 CPU 資源的,因此,才有了自旋限制!}但是我們也應該知道,不進入休眠而原地打轉,是會一直消耗CPU資源的,因此,才有了自旋限制!

看下面的JDK源碼:

?
1
2
3
4
5
6
7
8
9
10
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就是采用的自旋鎖方式,持續的嘗試讀取最新的 volatile 修飾的變量的值,并嘗試去用期望的值去比較,然后更新。

不過這里我們要注意,因為是無限循環,因此我們要保證占用資源的線程很快就能釋放,而不是長時間占用(當然,因為這里的源碼系統也設定了 int 型變量,因此,占用該變量的線程很快就會使用完而釋放)。

三、自旋鎖的死鎖

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

3.1、系統中斷

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

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

例如:由IO設備引起的中斷為硬件中斷,比如,鍵盤輸入,硬盤/光驅讀寫等;異常中斷很好理解,比如 NullPointerException 等。

3.2、中斷處理程序

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

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

參數含義如下:

  • irq: 中斷號,系統定義好,具體可查看中斷向量表;
  • handler: 中斷后發生的ISR(Interrupt Service Routines),直接翻譯為:中斷服務路由;實際類似,是響應中斷服務的程序;
  • flags: 中斷標志;
  • name: 中斷相關的設備的ASCII,如:"keyboard",這些名字會在 /proc/irq 和 /proc/interrupts 中使用;
  • dev: 用于共享中斷線,傳遞驅動程序的設備結構。非共享類型的中斷,直接設置成為 NULL

中斷標志(flags):

  • IRQF_DISABLED: 內核處理該ISR期間,禁止其它中斷(一般很少使用);
  • IRQF_SAMPLE_RANDOM: 表明該設備產生的中斷對內核熵池有貢獻;
  • IRQF_TIMER: 系統定時器;
  • IRQF_SHARED: 多個ISR共享中斷線,即一個中斷,可存在多個ISR;

調用 request_irq 成功時返回0,常見錯誤是 -EBUSY,表示給定的中斷線已經在使用(沒有指定IRQF_SHARED)。

注:

  1. 該函數可能引起睡眠,所以不允許在中斷上下文或者不允許睡眠的程序中使用!
  2. Linux 中的中斷處理程序是無須重入的。當給定的中斷處理程序正在執行的時候,其中斷線在所有的處理器上都會被屏蔽掉,以防在同一個中斷線上又接收到另一個新的中斷。通常情況下,除了該中斷的其他中斷都是打開的,也就是說其他的中斷線上的重點都能夠被處理,但是當前的中斷線總是被禁止的,故,同一個中斷處理程序是絕對不會被自己嵌套的。

那這和死鎖有何關系呢?額,下一小節會談到。但這里之所有提到中斷,是因為我們還要知道一件事,當系統產生中斷,程序被暫停時,程序是不能進入休眠的,此時程序只能采用一種方式:自旋,來保證不會睡眠。

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

3.3、中斷上下文 Context

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

中斷上下文:它與進程上下文不一樣,中斷上下文是內核正在執行ISR。ISR沒有自己獨立的棧,而是使用內核棧,大小一般是有限制的(32位是8KB大小)。同時,ISR是打斷了正常的程序流程,因此必須保證ISR執行速度快。正因為要執行速度快,所以,中斷上下文不允許睡眠,且不允許被阻塞!

大家可能會說了,執行速度快不允許睡眠,這解釋不合理,我睡眠個1ms不行么?嗯,下面我們就來分析下不能睡眠的真正原因:

1.中斷處理時,不會發生進程切換。

  • 因為能打斷當前中斷的只可能是更高優先級的中斷,其它進程的優先級是不會比中斷優先級更高的;
  • 如果中斷上下文休眠,則沒有辦法喚醒它,因為所有的 wake_up_xxx 是針對進程而言,而中斷沒有進程的概念;
  • 只要是中斷(硬中or軟中,不是香煙),都發生在內核,如果中斷上下文睡眠了,內核就阻塞了,系統能阻塞么?不能!阻塞了你就只能重啟機器了;

2.schedule 在切換進程時,會保存當前的進程上下文(CPU寄存器的值、狀態、堆棧SP內容)以便以后恢復再運行。中斷發生后,內核會保存當前被中斷進程的上下文。在ISR中,是中斷上下文,如果休眠或阻塞,則會調用 schedule,保存的進程上下文不是當前進程的上下文,所以不能在ISR中調用 schedule;
3.內核中 schedule 在進入時會判斷是否處于中斷上下文:

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

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

那還是沒有說自旋為何會死鎖?

自旋鎖是不能遞歸,否則自己等待自己已經獲取的鎖,將會導致死鎖!

一個線程獲取了一個自旋鎖,在執行這程中被中斷處理程序打斷,因此該線程只是暫停執行,并未退出,仍持有自旋鎖;而中斷處理程序嘗試獲取自旋鎖而獲取不到,只能自旋;這就造成一個事實:ISR拿不到自旋鎖,導致自旋而無法退出,該線程被中斷無法恢復執行至退出釋放自旋鎖,此時就造成了死鎖,導致系統崩潰。

四、死鎖解決

發生自旋鎖死鎖,往往因為單CPU這個臨界資源發生了搶占,使得一方持有自旋鎖被中斷暫停,一方不斷自旋來嘗試獲取自旋鎖。因此,在多CPU架構下,兩方如果分別運行在不同CPU上,是不會發生死鎖的。

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

  • 持有自旋鎖的線程(此時肯定在臨界區)不能休眠,休眠會引起進程切換,CPU就會被另一個進程占用等無法使用;
  • 持有自旋鎖的線程不允許被中斷,哪怕是ISR也不行,否則就存在ISR自旋;
  • 持有自旋鎖的線程,其內核不能被搶占,否則等同于CPU被搶占;

所以,根據以上總結一點:持有自旋鎖的線程,不能因為任何原因而放棄CPU! 也因此基于上述問題,自旋也需要添加一個上限時間以防死鎖。

linux上的自旋鎖有三種實現:

  1. 在單cpu,不可搶占內核中,自旋鎖為空操作。
  2. 在單cpu,可搶占內核中,自旋鎖實現為“禁止內核搶占”,并不實現“自旋”。(注意)
  3. 在多cpu,可搶占內核中,自旋鎖實現為“禁止內核搶占” + “自旋”。

以上就是Java 自旋鎖(spinlock)相關知識總結的詳細內容,更多關于Java 自旋鎖(spinlock)的資料請關注服務器之家其它相關文章!

原文鏈接:https://juejin.cn/post/6930427187237486605

延伸 · 閱讀

精彩推薦
825
Weibo Article 1 Weibo Article 2 Weibo Article 3 Weibo Article 4 Weibo Article 5 Weibo Article 6 Weibo Article 7 Weibo Article 8 Weibo Article 9 Weibo Article 10 Weibo Article 11 Weibo Article 12 Weibo Article 13 Weibo Article 14 Weibo Article 15 Weibo Article 16 Weibo Article 17 Weibo Article 18 Weibo Article 19 Weibo Article 20 Weibo Article 21 Weibo Article 22 Weibo Article 23 Weibo Article 24 Weibo Article 25
主站蜘蛛池模板: 国产免费网站视频 | 色婷婷综合久久久久中文 | 久草在线综合 | 亚洲一区中文字幕 | 亚洲成人免费网站 | 久久色播 | 久久9色 | 免费看毛片的网站 | hdbbwsexvideo| 91视频网页| 黄色特级毛片 | 精品亚洲一区二区三区 | 超久久| 日日狠狠久久偷偷四色综合免费 | 成人情欲视频在线看免费 | 国产污污视频 | 国产乱淫a∨片免费观看 | 欧美激情综合在线 | 国产精品高潮99久久久久久久 | 麻豆视频免费网站 | 毛片在线视频观看 | 国产午夜精品一区二区三区四区 | 一本免费视频 | 亚洲视频欧美 | 欧美精品18videos性欧美 | 羞羞电影在线观看www | 红杏网站永久免费视频入口 | 久久久电影电视剧免费看 | 欧美一级做一级爱a做片性 91在线视频观看 | 日韩黄色免费观看 | 免费一级毛片在线播放视频老 | 亚洲成人在线免费 | 青青草国产在线视频 | 免费激情网址 | 久久艹逼 | 成人444kkkk在线观看 | 国产深夜福利视频在线播放 | 在线a亚洲视频播放在线观看 | 亚洲国产精品久久久久久久 | 免费黄色大片网站 | 国产亚洲精品影达达兔 |