併發程式設計帶來的挑戰

學院講師直播助手發表於2020-12-23

一、 簡述鎖升級的流程和原理
為了防止多執行緒訪問共享資源造成執行緒阻塞的問題,並不會立馬對共享資源加重量級鎖,使執行緒進入BLOCKING狀態,而是先嚐試加偏向鎖,在一步步向輕量級鎖、重量級鎖膨脹的策略,如下圖所示:
image.png
**偏向鎖:**不存在資源競爭,資源總是由一個執行緒獲取的情況下使用。在物件頭儲存了當前執行緒的id.
**輕量級鎖:**如果偏向鎖被關閉或者已經被其他執行緒獲取,這種情況下搶佔同步鎖會膨脹到輕量級鎖。輕量級鎖會通過CAS操作(自旋),把鎖物件的標記欄位替換為一個指標指向當前執行緒棧幀中的LockRecord
**重量級鎖:**多個執行緒獲取同一個鎖的時候,虛擬機器就會阻塞未獲取到鎖的執行緒,並在目標鎖釋放的時候喚醒阻塞的執行緒。物件頭儲存了指向重量級鎖的指標。
總結:
**偏向鎖:**無實際競爭,且將來只有第一個申請鎖的執行緒會使用鎖。
**輕量級鎖:**無實際競爭,多個執行緒交替使用鎖;允許短時間的鎖競爭。
**重量級鎖:**有實際競爭,且鎖競爭時間長。

二、Synchronized的原理
synchronized有三種方式來加鎖,分別是:方法鎖,物件鎖synchronized(this),類鎖synchronized(Demo.Class)。其中在方法鎖層面可以有如下3種方式:

修飾例項方法,作用於當前例項加鎖,進入同步程式碼前要獲得當前例項的鎖
靜態方法,作用於當前類物件加鎖,進入同步程式碼前要獲得當前類物件的鎖
修飾程式碼塊,指定加鎖物件,對給定物件加鎖,進入同步程式碼庫前要獲得給定物件的鎖。
使用synchronized加鎖會從低到高逐步升級, 無鎖->偏向鎖->輕量級鎖->重量級鎖

重量級鎖通過物件內部的監視器(monitor)實現,一段被synchronized修飾的同步方法或者程式碼塊時,該執行緒得先獲取到synchronized修飾的物件對應的monitor,過程如下
image.png

三、執行緒是不是越多越好?為什麼?
不是,由於硬體資源的限制,執行緒過多會造成執行緒阻塞,阻塞或者喚醒一個執行緒時,都需要作業系統來幫忙,這就需要從使用者態轉換到核心態,而轉換狀態是需要消耗很多時間的,有可能比使用者執行程式碼的時間還要長。

四、wait和notify為什麼要加鎖
wait方法的語義有兩個,一個是釋放當前的物件鎖、另一個是使得當前執行緒進入阻塞佇列, 而這些操作都和監視器是相關的,所以wait必須要獲得一個監視器鎖。
  而對於notify來說也是一樣,它是喚醒一個執行緒,既然要去喚醒,首先得知道它在哪裡?所以就必須要找到這個物件獲取到這個物件的鎖,然後到這個物件的等待佇列中去喚醒一個執行緒。

作者:https://gper.club/articles/7e7e7f7ff3g5bgc0g69

相關文章