Java 併發編程面經

1 synchronized 關鍵字

  1. 使用 synchronized 關鍵字修飾的方法爲同步方法,由於 java 的每個對象都有一個內置鎖,當此關鍵字修飾方法時,內置鎖會保護整個方法。在調用該方法前,需要獲得內置鎖,否則就處於阻塞狀態。( synchronized 關鍵字也可以修飾靜態方法,此時如果調用該靜態方法,將會鎖住整個類)
  2. 有 synchronized 關鍵字修飾的語句塊被稱爲同步代碼塊,被該關鍵字修飾的語句塊會自動被加上內置鎖,從而實現同步。

2 什麼是可重入鎖?

可重入鎖表示鎖具有可重入性,例如 synchronized,ReentrantLock 都是可重入鎖。可重入性表明了鎖的分配機制:基於線程的分配,而不是基於方法調用的分配。舉個簡單的例子,當一個線程執行到某個 synchronized 方法時,比如說 method1,而在 method1 中會調用另外一個 synchronized 方法 method2,此時線程不必重新去申請鎖,而是可以直接執行方法 method2。

class MyClass {
    public synchronized void method1() {
        method2();
    }
     
    public synchronized void method2() {
         
    }
}

method1 和 method2 都用 synchronized 修飾了,假如某一時刻,線程A執行到了 method1,此時線程A獲取了這個對象的鎖,而由於 method2 也是 synchronized 方法,假如 synchronized 不具備可重入性,此時線程A需要重新申請鎖。但是這就會造成一個問題,因爲線程A已經持有了該對象的鎖,而又在申請獲取該對象的鎖,這樣就會線程A一直等待永遠不會獲取到的鎖。

而由於 synchronized 和 Lock 都具備可重入性,所以不會發生上述現象。

3 什麼是可中斷鎖?

可中斷鎖即可以相應中斷的鎖。Lock 是可中斷鎖,而 synchronized 不是可中斷鎖。如果某一線程A正在執行鎖中的代碼,另一線程B正在等待獲取該鎖,可能由於等待時間過長,線程B不想等待了,想先處理其他事情,我們可以讓它中斷自己或者在別的線程中中斷它,這種就是可中斷鎖。

4 什麼是公平鎖?

公平鎖即儘量以請求鎖的順序來獲取鎖。比如同時有多個線程在等待一個鎖,當這個鎖被釋放時,等待時間最久的線程(最先請求的線程)會獲得該鎖,這種就是公平鎖。非公平鎖無法保證鎖的獲取是否按照請求鎖的順序進行的,這樣就可能導致某個或者一些線程永遠獲取不到鎖。

synchronized 是非公平鎖,它無法保證等待的線程獲取鎖的順序。至於 ReentrantLock 和 ReentrantReadWriteLock,它默認情況下是非公平鎖,但是可以設置爲公平鎖。

5 synchronized 什麼情況下會釋放鎖?

  1. 獲取鎖的線程執行完了該代碼塊,然後線程釋放對鎖的佔有;
  2. 線程執行發生異常,此時 JVM 會讓線程自動釋放鎖。
  3. 調用 wait 方法,在等待的時候立即釋放鎖,方便其他的線程使用鎖.

6 Lock 和 synchronized 的區別?

  1. Lock 是一個接口,而 synchronized 是 Java 中的關鍵字,synchronized 是內置的語言實現
  2. synchronized 在發生異常時,會自動釋放線程佔有的鎖,因此不會導致死鎖現象發生;而 Lock 在發生異常時,如果沒有主動通過 unLock() 去釋放鎖,則很可能造成死鎖現象,因此使用 Lock 時需要在 finally 塊中釋放鎖
  3. Lock 可以讓等待鎖的線程響應中斷,而 synchronized 卻不行,使用 synchronized 時,等待的線程會一直等待下去,不能夠響應中斷
  4. 通過 Lock 可以知道有沒有成功獲取鎖,而 synchronized 卻無法辦到
  5. Lock 可以提高多個線程進行讀操作的效率。在性能上來說,如果競爭資源不激烈,兩者的性能是差不多的,而當競爭資源非常激烈時(即有大量線程同時競爭),此時 Lock 的性能要遠遠優於 synchronized。所以說,在具體使用時要根據適當情況選擇
  6. Lock 可以設置等待鎖的時間,而 synchronized 不行

7 什麼是 CAS?

CAS(Compare And Swap) 無鎖算法: CAS 是樂觀鎖技術,當多個線程嘗試使用 CAS 同時更新同一個變量時,只有其中一個線程能更新變量的值,而其它線程都失敗,失敗的線程並不會被掛起,而是被告知這次競爭中失敗,並可以再次嘗試。CAS 有3個操作數,內存值V,舊的預期值A,要修改的新值B。當且僅當預期值A和內存值V相同時,將內存值V修改爲B,否則什麼都不做。

8 線程池的作用有哪些?

線程池的作用: 在程序啓動的時候就創建若干線程來響應處理,它們被稱爲線程池,裏面的線程叫工作線程。線程池的作用如下:

  1. 降低資源消耗。通過重複利用已創建的線程降低線程創建和銷燬造成的消耗。
  2. 提高響應速度。當任務到達時,任務可以不需要等到線程創建就能立即執行。
  3. 提高線程的可管理性。

9 什麼是線程安全以及解決機制?

線程安全是指在多線程環境中能永遠保證程序的正確性,其實,只有存在共享數據時才需要考慮線程安全問題。當一個類被多個線程進行訪問並且正確運行,它就是線程安全的。

如何解決?

  • 加鎖:

a 鎖能使其保護的代碼以串行的形式來訪問,當給一個複合操作加鎖後,能使其成爲原子操作。一種錯誤的思想是隻要對寫數據的方法加鎖,其實這是錯的,對數據進行操作的所有方法都需加鎖,不管是讀還是寫

b 加鎖時需要考慮性能問題,不能總是一味地給整個方法加鎖 synchronized 就了事了,應該將方法中不影響共享狀態且執行時間比較長的代碼分離出去

c 加鎖的含義不僅僅侷限於互斥,還包括可見性。爲了確保所有線程都能看見最新值,讀操作和寫操作必須使用同樣的鎖對象

  • 不共享狀態:

無狀態對象: 無狀態對象(沒有字段和引用)一定是線程安全的,因爲不會影響到其他線程

線程關閉: 僅在單線程環境下使用

  • 不可變對象:

可以使用 final 修飾的對象保證線程安全,由於 final 修飾的引用型變量(除 String 外)不可變是指引用不可變,但其指向的對象是可變的,所以此類必須安全發佈,也即不能對外提供可以修改 final 對象的接口

10 死鎖

參考:什麼是死鎖?死鎖的預防?

11 關鍵字 volatile

關於 Java 關鍵字 volatile 的總結

12 synchronized 的實現原理

剖析 synchronized 的實現原理

13 JVM 對 synchronized 的優化

JVM 對 synchronized 的優化

14 Synchronized 與 Volatile 之間的區別

  1. Volatile 僅能使用在變量級別; Synchronized 則可以使用在變量、方法和同步代碼塊級別上。
  2. Volatile 僅能實現變量的修改可見性和有序性,並不能保證原子性;Synchronized 則可以保證變量的可見性、有序性、原子性。
  3. Volatile 不會造成線程的阻塞;Synchronized 可能會造成線程的阻塞。
  4. Volatile 標記的變量不會被編譯器優化; Synchronized 標記的變量可以被編譯器優化。

15 什麼是 Java 內存模型?

別再問什麼是Java內存模型了,看這裏!

16 Java 併發包都有哪些?

Java多線程進階(一)—— J.U.C併發包概述

參考:解釋一下鎖的一些基本概念:可重入鎖、可中斷鎖、公平鎖、讀寫鎖
synchronized和ReentrantLock有什麼區別
Java併發 - 什麼是線程安全(一).

發佈了123 篇原創文章 · 獲贊 226 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章