2020最全的併發編程篇:知識圖鑑+知識點剖析+高頻面試+書籍

知識圖鑑(我真的盡力清晰了)

2020最全的併發編程篇:知識圖鑑+知識點剖析+高頻面試+書籍

知識點剖析

1、JAVA 併發知識庫

2020最全的併發編程篇:知識圖鑑+知識點剖析+高頻面試+書籍
2、JAVA 線程實現/創建方式

2020最全的併發編程篇:知識圖鑑+知識點剖析+高頻面試+書籍
3、4 種線程池

Java 裏面線程池的頂級接口是 Executor,但是嚴格意義上講 Executor 並不是一個線程池,而只是一個執行線程的工具。真正的線程池接口是 ExecutorService。

2020最全的併發編程篇:知識圖鑑+知識點剖析+高頻面試+書籍
4、線程生命週期(狀態)

當線程被創建並啓動以後,它既不是一啓動就進入了執行狀態,也不是一直處於執行狀態。在線程的生命週期中,它要經過新建(New)、就緒(Runnable)、運行(Running)、阻塞(Blocked)和死亡(Dead)5 種狀態。尤其是當線程啓動以後,它不可能一直"霸佔"着 CPU 獨自運行,所以 CPU 需要在多條線程之間切換,於是線程狀態也會多次在運行、阻塞之間切換

5、終止線程 4 種方式

6、sleep 與 wait 區別

7、start 與 run 區別

8、後臺線程

9、JAVA 鎖

10、線程基本方法

11、線程上下文切換

12、同步鎖與死鎖

13、線程池原理

14、JAVA 阻塞隊列原理

15、…………

2020最全的併發編程篇:知識圖鑑+知識點剖析+高頻面試+書籍

內容太多,就不一一列舉了,需要完整文檔的夥伴
添加VX:13272413561(備註51)
即可獲取全套併發編程資料!!走過路過不要錯過!!!!

高頻面試題

Synchronized 相關問題

問題一: Synchronized 用過嗎, 其原理是什麼?

這是一道 Java 面試中幾乎百分百會問到的問題, 因爲沒有任何寫過併發程序的開發者會沒聽說或者沒接觸過 Synchronized。

Synchronized 是由 JVM 實現的一種實現互斥同步的一種方式, 如果你查看被Synchronized 修飾過的程序塊編譯後的字節碼, 會發現, 被 Synchronized 修飾過的程序塊, 在編譯前後被編譯器生成了monitorenter 和 monitorexit 兩個字節碼指令。

這兩個指令是什麼意思呢?

在虛擬機執行到 monitorenter 指令時, 首先要嘗試獲取對象的鎖: 如果這個對象沒有鎖定, 或者當前線程已經擁有了這個對象的鎖, 把鎖的 計 數 器

+1; 當 執 行 monitorexit 指 令 時 將 鎖 計 數 器

-1; 當 計 數 器爲 0 時 , 鎖 就 被 釋 放 了 。

如果獲取對象失敗了, 那當前線程就要阻塞等待, 直到對象鎖被另外一個線程釋放爲止。Java中Synchronize通 過 在 對 象 頭 設 置 標 記 , 達 到 了 獲 取 鎖 和 釋 放鎖 的 目 的 。

問題二: 你剛纔提到獲取對象的鎖, 這個“ 鎖” 到底是什麼? 如何確定對象的鎖?

“ 鎖” 的本質其實是 monitorenter 和 monitorexit 字節碼指令的一個 Reference

類型的參數, 即要鎖定和解鎖的對象。 我們知道, 使用Synchronized 可以修飾不同的對象, 因此, 對應的對象鎖可以這麼確定。

  1. 如果 Synchronized 明確指定了鎖對象, 比如 Synchronized( 變量名) 、 Synchronized( this) 等, 說明加解鎖對象爲該對象。

  2. 如 果 沒 有 明 確 指 定 :

若 Synchronized 修飾的方法爲非靜態方法, 表示此方法對應的對象爲鎖對象;

若 Synchronized 修飾的方法爲靜態方法, 則表示此方法對應的類對象爲鎖對象。

注意, 當一個對象被鎖住時, 對象裏面所有用 Synchronized 修飾的方法都將產生

堵塞, 而對象裏非 Synchronized 修飾的方法可正常被調用, 不受鎖影響。

問題三: 什麼是可重入性, 爲什麼說 Synchronized 是可重入鎖?
可 重 入 性是 鎖 的 一 個 基 本 要 求 , 是 爲 了 解 決 自 己 鎖 死 自 己 的 情 況 。 比 如下面的僞代碼, 一個類中的同步方法調用另一個同步方法, 假如Synchronized 不 支 持 重 入 , 進 入 method 2 方 法 時 當 前 線 程 獲 得 鎖 ,method 2 方法裏面執行 method 1 時當前線程又要去嘗試獲取鎖, 這時如果不支持重入, 它就要等釋放, 把自己阻塞, 導致自己鎖死自己。對 Synchronized 來說, 可重入性是顯而易見的, 剛纔提到, 在執行monitorenter 指令時, 如果這個對象沒有鎖定, 或者當前線程已經擁有了這個對象的鎖( 而不是已擁有了鎖則不能繼續獲取) , 就把鎖的計數器 + 1 ,其實本質上就通過這種方式實現了可重入性。

問題四: JVM 對 Java 的原生鎖做了哪些優化?

在 Java 6 之 前 , Monitor 的 實 現 完 全 依 賴 底 層 操 作 系 統 的 互 斥 鎖 來實 現 , 也 就 是 我 們 剛 才 在 問 題 二 中 所 闡 述 的 獲 取 /釋 放 鎖 的 邏 輯 。由 於 Java 層 面 的 線 程 與 操作 系 統 的 原 生 線 程 有 映 射 關 系 , 如 果 要 將 一個 線 程 進 行 阻 塞 或 喚 起 都 需 要 操 作 系 統 的 協 助 , 這 就 需 要 從 用 戶 態 切 換到 內 核 態 來 執 行 , 這 種 切 換 代 價 十 分 昂 貴 , 很 耗 處 理 器 時 間 , 現 代 JDK中 做 了 大 量 的 優 化 。一種優化是使用自旋鎖, 即在把線程進行阻塞操作之前先讓線程自旋等待一段時間,可能在等待期間其他線程已經解鎖, 這時就無需再讓線程執行阻塞操作, 避免了用戶態到內核態的切換。現代 JDK 中還提供了三種不同的Monitor 實現, 也就是三種不同的鎖:

 偏 向 鎖 ( Biased Locking)

 輕量級 鎖

 重量級 鎖

這 三 種 鎖 使 得 JDK 得 以 優 化 Synchronized 的 運 行 , 當 JVM 檢 測到 不 同 的 競 爭 狀 況 時 , 會 自 動 切 換 到 適 合 的 鎖 實 現 , 這 就 是 鎖 的 升 級 、降 級 。

 當沒有 競爭出現 時, 默認會 使用偏向 鎖。JVM 會 利 用 CAS 操 作 , 在 對 象 頭 上 的 Mark Word 部 分 設 置 線 程ID, 以 表 示 這 個 對 象 偏 向 於 當 前 線 程 , 所 以 並 不 涉 及 真 正 的 互 斥 鎖 , 因爲 在 很 多 應 用 場 景 中 , 大 部 分 對 象 生 命 周 期 中 最 多 會 被 一 個 線 程 鎖 定 ,使 用 偏 斜 鎖 可 以 降 低 無 競 爭 開 銷 。

 如 果 有 另 一 線 程 試 圖 鎖 定 某 個 被 偏 斜 過 的 對 象 , JVM就 撤 銷 偏 斜 鎖 ,切 換 到 輕 量 級 鎖 實 現 。

 輕量級 鎖依賴 CAS 操作 Mark Word 來試圖獲取鎖, 如果重試成功, 就使用普通的輕量級鎖; 否則, 進一步升級爲重量級鎖。

問題五: 爲什麼說 Synchronized 是非公平鎖?

非公平主要表現在獲取鎖的行爲上, 並非是按照申請鎖的時間前後給等待線程分配鎖的, 每當鎖被釋放後, 任何一個線程都有機會競爭到鎖, 這樣做的目的是爲了提高執行性能, 缺點是可能會產生線程飢餓現象。

問題六: 什麼是鎖消除和鎖粗化?

1.鎖消除: 指虛擬機即時編譯器在運行時, 對一些代碼上要求同步, 但被檢測 到 不 可 能 存 在 共 享 數 據 競 爭 的 鎖 進 行 消 除 。 主 要 根 據 逃 逸 分 析 。 程 序員 怎 麼 會 在 明 知 道 不 存 在 數 據 競 爭 的 情 況 下 使 用 同 步 呢 ? 很 多 不 是 程 序員 自 己 加 入 的 。

2.鎖粗化: 原則上, 同步塊的作用範圍要儘量小。 但是如果一系列的連續操作 都 對 同 一 個 對 象 反 復 加 鎖 和 解 鎖 , 甚 至 加 鎖 操 作 在 循 環 體 內 , 頻 繁 地進 行 互 斥 同 步 操 作 也 會 導 致 不 必 要 的 性 能 損 耗 。鎖粗化就是增大鎖的作用域。

問題七: 爲什麼說Synchronized是一個悲觀鎖? 樂觀鎖的實現原理又是什麼? 什麼是CAS, 它有什麼特性?

Synchronized 顯然是一個悲觀鎖, 因爲它的併發策略是悲觀的:

不管是否會產生競爭, 任何的數據操作都必須要加鎖、 用戶態核心態轉換、 維護鎖計數器和檢查是否有被阻塞的線程需要被喚醒等操作。隨着硬件指令集的發展, 我們可以使用基於衝突檢測的樂觀併發策略。先進行操作,如果沒有其他線程徵用數據, 那操作就成功了;

如 果 共 享 數 據 有 徵 用 , 產 生 了 衝 突 , 那 就 再 進 行 其 他 的 補 償 措 施 。 這 種樂 觀 的 並 發 策 略 的 許 多 實 現 不 需 要 線 程 掛 起 , 所 以 被 稱 爲 非 阻 塞 同 步 。樂 觀 鎖 的 核 心 算 法 是 CAS( Compareand Swap, 比 較 並 交 換 ) , 它 涉及 到 三 個 操 作 數 : 內 存 值 、 預 期 值 、 新 值 。 當 且 僅 當 預 期 值 和 內 存 值 相等 時 才 將 內 存 值 修 改 爲 新 值 。

這樣處理的邏輯是, 首先檢查某塊內存的值是否跟之前我讀取時的一樣, 如不一樣則表示期間此內存值已經被別的線程更改過, 捨棄本次操作, 否則說明期間沒有其他線程對此內存值操作, 可以把新值設置給此塊內存。

CAS 具有原子性, 它的原子性由 CPU 硬件指令實現保證, 即使用JNI 調用Native 方法調用由 C++ 編寫的硬件級別指令, JDK 中提供了 Unsafe 類執行這些操作。

問題八: 樂觀鎖一定就是好的嗎?

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

  1. 樂觀鎖 只能保證 一個共享 變量的原 子操作。 如果多 一個或幾 個變量, 樂觀鎖將變得力不從心, 但互斥鎖能輕易解決, 不管對象數量多少及對象顆粒度大小。

  2. 長 時 間 自 旋 可 能 導 致 開 銷 大 。 假 如 CAS 長 時 間 不 成 功 而 一 直 自 旋 , 會給 CPU 帶 來 很 大 的 開 銷 。

  3. ABA 問 題 。 CAS 的 核 心 思 想 是 通 過 比 對 內 存 值 與 預 期 值 是 否 一 樣 而 判斷 內 存 值 是 否 被 改 過 , 但 這 個 判 斷 邏 輯 不 嚴 謹 , 假 如 內 存 值 原 來 是A,後來被一條線程改爲 B, 最後又被改成了 A, 則 CAS 認爲此內存值並沒有發生改變, 但實際上是有被其他線程改過的, 這種情況對依賴過程值的情景的運算結果影響很大。 解決的思路是引入版本號, 每次變量更新都把版本號加一。

可 重 入 鎖 ReentrantLock 及 其 他 顯 式 鎖 相 關 問 題:

問題一: 跟Synchronized相比, 可重入鎖Reentrant Lock其實現原理有什麼不同?

問題二: 那麼請談談 AQS 框架是怎麼回事兒?

問題三: 請儘可能詳盡地對比下Synchronized和Reentrant Lock的異同。

問題四: Reentrant Lock 是如何實現可重入性的?

問題五: 除了 Reetrant Lock, 你還接觸過 JUC 中的哪些併發工具?

問題六: 請談談 Read Write Lock 和 Stamped Lock。

問題七: 如何讓 Java 的線程彼此同步? 你瞭解過哪些同步器? 請分別介紹下。

問題八: Cyclic Barrier和Count Down Latch 看起來很相似, 請對比下呢?

Java 線程池相關問題

問題一: Java 中的線程池是如何實現的?

問題二: 創建線程池的幾個核心構造參數?

問題三: 線程池中的線程是怎麼創建的? 是一開始就隨着線程池的啓動創建好的嗎?

問題四: 既然提到可以通過配置不同參數創建出不同的線程池, 那麼Java 中默認實現好的

線程池又有哪些呢? 請比較它們的異同。

問題五: 如何在 Java 線程池中提交線程?

Java 內存模型相關問題
問題一: 什麼是 Java 的內存模型, Java中各個線程是怎麼彼此看到對方的變量的?

問題二: 請談談 volatile 有什麼特點, 爲什麼它能保證變量對所有線程的可見性?

問題三: 既然 volatile 能夠保證線程間的變量可見性, 是不是就意味着基於volatile 變量的運算就是併發安全的?

問題四: 請對比下 volatile 對比 Synchronized 的異同。

問題五: 請談談 Thread Local 是怎麼解決併發安全的?

問題六: 很多人都說要慎用 Thread Local, 談談你的理解, 使用Thread Local 需要注意些什麼?

Java併發編程實戰(中文版)

2020最全的併發編程篇:知識圖鑑+知識點剖析+高頻面試+書籍
2020最全的併發編程篇:知識圖鑑+知識點剖析+高頻面試+書籍

清晰的知識圖譜(原圖)、完整知識點剖析(PDF文檔)、高頻面試題+答案(PDF文檔)、Java併發編程實戰(PDF文檔),這些資料都免費送哦,正在爲面試準備或準備重溫知識提升自我的小夥伴添加VX:13272413561(備註51)
即可免費獲取全套併發編程學習資料哦!!還有更多資料等着你!!

2020最全的併發編程篇:知識圖鑑+知識點剖析+高頻面試+書籍
2020最全的併發編程篇:知識圖鑑+知識點剖析+高頻面試+書籍

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章