面試題之併發相關專欄二

一、什麼是鎖消除和鎖粗化?

  • 鎖消除:指虛擬機即時編譯器在運行時,對一些代碼上要求同步,但被檢測到不可能存在共享數據競爭的鎖進行消除。
  • 鎖粗化:原則上,同步塊的作用範圍應該儘可能的小,也就是說鎖的粒度要儘可能小一點。但是如果一系列的連續操作都對同一個對象反覆加鎖和解鎖,甚至加鎖操作在循環體內,頻繁地進行互斥同步也會導致不必要的性能損耗,鎖粗化就是增大鎖的作用範圍。

二、爲什麼說Synchronized是一個悲觀鎖?

Synchronized顯然是悲觀的,不管是否會產生競爭,任何的數據操作都必須要加鎖、維護鎖的計數器和檢查是否有被阻塞的線程需要被喚醒等操作。

三、樂觀鎖的實現原理是什麼?什麼是CAS,它有什麼特性?

隨着硬件指令集的發展,我們可以使用基於衝突檢測的樂觀併發策略,先進行操作,如果沒有其他線程徵用數據,那操作就成功了;如果共享數據有徵用,產生了衝突,那就再進行其他的補償措施,這種樂觀的併發策略的許多實現不需要線程掛起,所以被稱爲非阻塞同步。

樂觀鎖的核心就是CAS算法(CompareAndSwap算法),指的是比較且交換,它涉及到三個操作數: 內存值、預估值、新值。當且僅當預估值和內存值相同時纔將內存值更新爲新值。這樣處理的邏輯是,首先檢查某塊內存的值是否跟之前我讀取時的一樣,如不一樣表示期間此內存值已經被別的線程修改過,捨棄本次操作,否則說明期間沒有其他線程對此內存值操作,可以把新值設置給此塊內存。CAS具有原子性,它的原子性由CPU硬件指令實現保證,即使用JNI調用Native本地方法調用由C++編寫的硬件級別指令,JDK中提供了Unsafe類執行這些操作。

四、樂觀鎖一定是好的嗎?

樂觀鎖避免了悲觀鎖獨佔對象德現象,同時提高了併發性能,但它也有缺點。

  • 樂觀鎖只能保證一個共享變量的原子操作,如果多一個或幾個變量,樂觀鎖就顯得力不從心了,但互斥鎖能輕鬆解決在該問題,不管對象數量多少和對象顆粒度大小;
  • 長時間自旋可能導致開銷很大,加入CAS長時間不成功而一直自旋,會給CPU帶來很大的開銷;
  • ABA問題,CAS的核心思想是通過對比內存值和預估值是否一樣而判斷內存值是否有被改過,這個判斷邏輯並不嚴謹,ABA問題,就是說一個線程把數據A變爲了B,然後又重新變成了A。此時另外一個線程讀取的時候,發現A沒有變化,就誤以爲是原來的那個A,則CAS認爲此內存值並沒有發生改變,但實際上是有被其他線程改過的。解決的思路就是引入版本號, 每次變量更新都把版本號加1;

五、請說出 Synchronized和ReentrantLock的異同?

ReentrantLock的功能比ReentrantLock強大,主要的不同點如下圖所示: