原始碼都背下來了,你給我看這
我是 javapub,一名 Markdown 程式員從?????,八股文種子選手,
面試官: 你好,我看到你的簡歷上寫著你熟悉 Java 中的 "synchronized" 關鍵字,你能給我講講它的作用嗎?
候選人: 當然,"synchronized" 是 Java 中的一個關鍵字,用于實作同步機制,它可以用來修飾方法或代碼塊,以確保在同一時間只有一個執行緒可以訪問被修飾的代碼,
面試官: 很好,那么,你能舉個例子來說明 "synchronized" 關鍵字的使用方法嗎?
候選人: 當然,你可以使用 "synchronized" 關鍵字來修飾方法或代碼塊,例如,你可以這樣使用:
public synchronized void doSomething() {
// ...
}
在上面的代碼中,"synchronized" 關鍵字修飾了 "doSomething()" 方法,這意味著在同一時間只有一個執行緒可以訪問該方法,
面試官: 很好,那么,如果我想修飾一個代碼塊,應該怎么做呢?
候選人: 你可以這樣使用 "synchronized" 關鍵字來修飾一個代碼塊:
public void doSomething() {
synchronized (this) {
// ...
}
}
在上面的代碼中,"synchronized" 關鍵字修飾了一個代碼塊,該代碼塊使用 "this" 作為鎖物件,這意味著在同一時間只有一個執行緒可以訪問該代碼塊,
面試官: 很好,那么,你能解釋一下 "synchronized" 關鍵字的實作原理嗎?
候選人: 當一個執行緒訪問一個被 "synchronized" 關鍵字修飾的方法或代碼塊時,它會嘗試獲取該物件的監視器鎖,如果該鎖已經被其他執行緒持有,則該執行緒將被阻塞,直到該鎖被釋放,下面是一個使用 "synchronized" 關鍵字的示例:
public class Counter {
private int count = 0;
public synchronized void increment() {
count++;
}
public synchronized void decrement() {
count--;
}
public synchronized int getCount() {
return count;
}
}
在上面的代碼中,"increment()"、"decrement()" 和 "getCount()" 方法都被 "synchronized" 關鍵字修飾,這意味著在同一時間只有一個執行緒可以訪問這些方法,
面試官: 很好,你對 "synchronized" 關鍵字的理解很清晰,那么,你能告訴我 "synchronized" 關鍵字的缺點嗎?
候選人: 當然,使用 "synchronized" 關鍵字會帶來一些性能上的開銷,因為每個執行緒都需要獲取鎖才能訪問被修飾的代碼,此外,如果使用不當,還可能會導致死鎖等問題,
面試官: 那么,你能告訴我如何避免 "synchronized" 關鍵字帶來的性能開銷嗎?
候選人: 當然,一種方法是使用 "volatile" 關鍵字來修飾變數,這可以確保變數的可見性,而不需要使用鎖,另一種方法是使用 "java.util.concurrent" 包中的并發集合類,例如 ConcurrentHashMap、CopyOnWriteArrayList 等,這些類使用了更高效的同步機制,可以避免 "synchronized" 關鍵字帶來的性能開銷,
面試官: 很好,你的回答很不錯,那么,你能告訴我 "synchronized" 關鍵字和 "Lock" 介面之間的區別嗎?
候選人: 當然, "synchronized" 關鍵字是 Java 中內置的同步機制,它可以用來修飾方法或代碼塊,使用起來比較簡單,但是它的性能開銷比較大,而 "Lock" 介面是 Java 中提供的一種更加靈活的同步機制,它可以實作更細粒度的鎖控制,例如可重入鎖、讀寫鎖等,使用起來比較復雜,但是它的性能開銷比較小,
面試官: 很好,你的回答很清晰,那么,你有沒有使用過 "Lock" 介面呢?
候選人: 是的,我有使用過 "Lock" 介面,例如,我曾經使用過 ReentrantLock 類來實作可重入鎖,這可以避免 "synchronized" 關鍵字的性能開銷,并且可以實作更細粒度的鎖控制,
面試官: 很好,你的經驗很豐富,那么,你能告訴我 "Lock" 介面的一些特點嗎?
候選人: 當然, "Lock" 介面的一些特點包括:
- 可以實作更細粒度的鎖控制,例如可重入鎖、讀寫鎖等,
- 可以實作公平鎖和非公平鎖,
- 可以實作超時鎖和可中斷鎖,
- 可以實作多個條件變數,可以更加靈活地控制執行緒的等待和喚醒,
面試官: 那么,你能告訴我 "synchronized" 關鍵字和 "volatile" 關鍵字之間的區別嗎?
候選人: 當然, "synchronized" 關鍵字和 "volatile" 關鍵字都可以用來實作多執行緒之間的同步,但是它們的作用不同, "synchronized" 關鍵字可以確保在同一時間只有一個執行緒可以訪問被修飾的代碼,而 "volatile" 關鍵字可以確保變數的可見性,即當一個執行緒修改了變數的值后,其他執行緒可以立即看到這個修改,
面試官: 看來你使用的很好,下面問一點深入的東西,回答不上來也沒關系,可以自己想想,
面試官: 好的,那么你能夠從 "synchronized" 的底層 Java 實作角度,解釋一下它的實作原理嗎?
候選人: 當一個執行緒訪問一個被 "synchronized" 關鍵字修飾的方法或代碼塊時,它會嘗試獲取該物件的監視器鎖,如果該鎖已經被其他執行緒持有,則該執行緒將被阻塞,直到該鎖被釋放,在 Java 中,每個物件都有一個監視器鎖,也稱為內部鎖或互斥鎖,當一個執行緒獲取了一個物件的監視器鎖后,其他執行緒就無法訪問該物件的被 "synchronized" 關鍵字修飾的方法或代碼塊,直到該鎖被釋放,
在 Java 中,"synchronized" 關鍵字的實作是基于物件頭中的標記字,當一個物件被鎖定時,它的標記字會被設定為鎖定狀態,當鎖被釋放時,標記字會被清除,在 Java 6 及之前的版本中,物件頭中的標記字是 32 位的,其中 25 位用于存盤物件的哈希碼,4 位用于存盤物件的分代年齡,2 位用于存盤鎖標志位,1 位用于存盤是否是偏向鎖,在 Java 7 及之后的版本中,物件頭中的標記字被重新設計,其中 32 位用于存盤物件的哈希碼和分代年齡,而鎖標志位則被存盤在一個單獨的資料結構中,
面試官: 很好,你的回答很詳細,那么,你能夠給我講講 "synchronized" 關鍵字的優化策略嗎?
候選人: 當然,在 Java 中,"synchronized" 關鍵字的性能開銷比較大,因為每個執行緒都需要獲取鎖才能訪問被修飾的代碼,為了優化 "synchronized" 關鍵字的性能,Java 6 及之后的版本中引入了偏向鎖、輕量級鎖和重量級鎖等優化策略,
偏向鎖是一種針對單執行緒訪問同步塊的優化策略,當一個執行緒訪問一個被 "synchronized" 關鍵字修飾的代碼塊時,它會嘗試獲取該物件的偏向鎖,如果該鎖沒有被其他執行緒持有,則該執行緒可以直接獲取該鎖,而無需進行同步操作,如果該鎖已經被其他執行緒持有,則該執行緒會嘗試升級為輕量級鎖或重量級鎖,
輕量級鎖是一種針對多執行緒訪問同步塊的優化策略,當一個執行緒訪問一個被 "synchronized" 關鍵字修飾的代碼塊時,它會嘗試獲取該物件的輕量級鎖,如果該鎖沒有被其他執行緒持有,則該執行緒可以直接獲取該鎖,而無需進行同步操作,如果該鎖已經被其他執行緒持有,則該執行緒會嘗試自旋等待該鎖的釋放,
重量級鎖是一種針對多執行緒訪問同步塊的默認策略,當一個執行緒訪問一個被 "synchronized" 關鍵字修飾的代碼塊時,它會嘗試獲取該物件的重量級鎖,如果該鎖沒有被其他執行緒持有,則該執行緒可以直接獲取該鎖,而無需進行同步操作,如果該鎖已經被其他執行緒持有,則該執行緒會被阻塞,直到該鎖被釋放,
面試官: 很好,你的回答很詳細,那么,你能夠給我講講 "synchronized" 關鍵字的底層 Java 原始碼實作嗎?
候選人: 當然,在 Java 中,"synchronized" 關鍵字的底層實作是通過 monitorenter 和 monitorexit 指令來實作的,當一個執行緒訪問一個被 "synchronized" 關鍵字修飾的方法或代碼塊時,它會嘗試獲取該物件的監視器鎖,這可以通過 monitorenter 指令來實作,當該執行緒執行完被 "synchronized" 關鍵字修飾的方法或代碼塊后,它會釋放該物件的監視器鎖,這可以通過 monitorexit 指令來實作,
參考底層指令:
以下是 JVM 中與 "synchronized" 相關的原始碼:
- monitorenter 指令的實作:
void Interpreter::monitorenter() {
oop obj = stack_top().get_obj(); // 獲取堆疊頂元素,即被鎖定的物件
if (obj == NULL) { // 如果物件為空,則拋出 NullPointerException 例外
THROW(vmSymbols::java_lang_NullPointerException());
}
BasicLock* lock = obj->mark()->lock(); // 獲取物件的鎖
if (lock->displaced_header() == NULL) { // 如果鎖沒有被其他執行緒持有,則嘗試獲取鎖
// Fast path: lock is unheld, try to acquire it
if (lock->displaced_header() == NULL &&
lock->displaced_owner() == NULL &&
lock->set_displaced_header()) {
// Lock acquired
return; // 獲取鎖成功,直接回傳
}
}
// Slow path: lock is held or contention detected
InterpreterRuntime::monitorenter(THREAD, obj); // 獲取鎖失敗,呼叫 InterpreterRuntime::monitorenter() 方法進行同步操作
}
在上面的代碼中,monitorenter 指令的實作是通過獲取物件的鎖來實作的,如果該鎖沒有被其他執行緒持有,則該執行緒可以直接獲取該鎖,而無需進行同步操作,如果該鎖已經被其他執行緒持有,則該執行緒會嘗試升級為輕量級鎖或重量級鎖,
- monitorexit 指令的實作:
void Interpreter::monitorexit() {
oop obj = stack_top().get_obj(); // 獲取堆疊頂元素,即被鎖定的物件
if (obj == NULL) { // 如果物件為空,則拋出 NullPointerException 例外
THROW(vmSymbols::java_lang_NullPointerException());
}
BasicLock* lock = obj->mark()->lock(); // 獲取物件的鎖
if (lock->displaced_header() == THREAD) { // 如果鎖被當前執行緒持有,則直接釋放鎖
// Fast path: lock is held by this thread, release it
lock->clear_displaced_header();
return; // 釋放鎖成功,直接回傳
}
// Slow path: lock is held by another thread or unheld
InterpreterRuntime::monitorexit(THREAD, obj); // 釋放鎖失敗,呼叫 InterpreterRuntime::monitorexit() 方法進行同步操作
}
在上面的代碼中,monitorexit 指令的實作是通過釋放物件的鎖來實作的,如果該鎖被當前執行緒持有,則該執行緒可以直接釋放該鎖,而無需進行同步操作,如果該鎖被其他執行緒持有,則該執行緒會被阻塞,直到該鎖被釋放,
- ObjectMonitor 類的實作:
class ObjectMonitor : public CHeapObj<mtSynchronizer> {
friend class VMStructs;
private:
volatile intptr_t _header; // 物件頭,用于存盤鎖狀態和其他資訊
volatile intptr_t _count; // 計數器,用于記錄重入次數
volatile intptr_t _waiters; // 等待佇列長度,用于記錄等待鎖的執行緒數
volatile intptr_t _recursions; // 遞回深度,用于記錄當前執行緒已經獲取鎖的次數
volatile intptr_t _object; // 物件指標,指向被鎖定的物件
volatile intptr_t _owner; // 持有者指標,指向當前持有鎖的執行緒
volatile intptr_t _WaitSet; // 等待佇列頭指標,指向等待佇列的頭節點
volatile intptr_t _EntryList; // 等待佇列尾指標,指向等待佇列的尾節點
volatile intptr_t _cxq; // 等待佇列的條件變數,用于支持條件變數的等待和喚醒操作
volatile intptr_t _FreeNext; // 空閑鏈表指標,用于回收 ObjectMonitor 物件
volatile intptr_t _Responsible; // 責任執行緒指標,用于記錄最后一個釋放鎖的執行緒
volatile intptr_t _SpinFreq; // 自旋頻率,用于控制自旋等待的時間
volatile intptr_t _SpinClock; // 自旋時鐘,用于記錄自旋等待的時間
volatile intptr_t _SpinDuration; // 自旋持續時間,用于控制自旋等待的時間
volatile intptr_t _SpinEarly; // 自旋提前量,用于控制自旋等待的時間
volatile intptr_t _contentions; // 競爭次數,用于記錄獲取鎖的競爭次數
volatile intptr_t _succ; // 成功次數,用于記錄獲取鎖的成功次數
volatile intptr_t _cxqWaitTime; // 條件變數等待時間,用于記錄條件變數等待的時間
volatile intptr_t _reserved; // 保留欄位,用于未來擴展
static int _header_offset; // 物件頭偏移量,用于訪問物件頭中的資訊
static int _count_offset; // 計數器偏移量,用于訪問計數器中的資訊
static int _waiters_offset; // 等待佇列長度偏移量,用于訪問等待佇列長度中的資訊
static int _recursions_offset; // 遞回深度偏移量,用于訪問遞回深度中的資訊
static int _object_offset; // 物件指標偏移量,用于訪問物件指標中的資訊
static int _owner_offset; // 持有者指標偏移量,用于訪問持有者指標中的資訊
static int _WaitSet_offset; // 等待佇列頭指標偏移量,用于訪問等待佇列頭指標中的資訊
static int _EntryList_offset; // 等待佇列尾指標偏移量,用于訪問等待佇列尾指標中的資訊
static int _cxq_offset; // 條件變數偏移量,用于訪問條件變數中的資訊
static int _FreeNext_offset; // 空閑鏈表指標偏移量,用于訪問空閑鏈表指標中的資訊
static int _Responsible_offset; // 責任執行緒指標偏移量,用于訪問責任執行緒指標中的資訊
static int _SpinFreq_offset; // 自旋頻率偏移量,用于訪問自旋頻率中的資訊
static int _SpinClock_offset; // 自旋時鐘偏移量,用于訪問自旋時鐘中的資訊
static int _SpinDuration_offset; // 自旋持續時間偏移量,用于訪問自旋持續時間中的資訊
static int _SpinEarly_offset; // 自旋提前量偏移量,用于訪問自旋提前量中的資訊
static int _contentions_offset; // 競爭次數偏移量,用于訪問競爭次數中的資訊
static int _succ_offset; // 成功次數偏移量,用于訪問成功次數中的資訊
static int _cxqWaitTime_offset; // 條件變數等待時間偏移量,用于訪問條件變數等待時間中的資訊
static int _reserved_offset; // 保留欄位偏移量,用于訪問保留欄位中的資訊
...
};
在上面的代碼中,ObjectMonitor 類是 JVM 中與 "synchronized" 相關的核心類之一,它包含了物件的監視器鎖的狀態資訊,例如鎖的持有者、等待佇列、遞回深度等,在 Java 中,每個物件都有一個 ObjectMonitor 物件與之對應,用于實作 "synchronized" 關鍵字的同步機制,
面試官: 很好,你的回答很全面,你已進入候補名單,有訊息會通知你,
候選人: 原始碼都背下來了,你給我看這,

最近我在更新《面試1v1》系列文章,主要以場景化的方式,講解我們在面試中遇到的問題,致力于讓每一位工程師拿到自己心儀的offer,感興趣可以關注JavaPub追更!
??目錄合集:
Gitee:https://gitee.com/rodert/JavaPub
GitHub:https://github.com/Rodert/JavaPub
http://javapub.net.cn
文章串列
??最少必要面試題
- Java基礎
- Java并發入門
- Java容器
- JavaWeb
- JVM
- MySQL
- MyBatis
- Spring
- SpringBoot
- Redis
- ElasticSearch
- [Kafka]
- Zookeeper
- Docker
- 快取
??知識點總結
下面是原創PDF干貨版,持續更新中,
-
51頁的MyBatis
-
14頁的zookeeper總結
...
??Java基礎
鎖
- volatile關鍵字的作用
jdk8
- 原來ThreadLocal的Lambda構造方式這么簡單
??資料結構與演算法
- 冒泡排序就是這么容易
- 選擇排序就是這么容易
- 插入排序就是這么容易
- 希爾排序就是這么容易
- 歸并排序就是這么容易
- 快速排序就是這么容易
- 堆排序就是這么容易
- 計數排序就是這么容易
- 桶排序就是這么容易
- 基數排序就是這么容易
- rodert熬夜寫了一份BloomFilter總結
- 哈希演算法篇 - 布隆過濾器
- B樹和B+樹的區別
??Mybatis
- rodert熬夜寫了一份Mybatis總結
- MyBatis SQL 批量更新(代碼+案例)
??搜索
Lucene
- Lucene就是這么容易
Elasticsearch
- Springboot2.x整合ElasticSearch7.x實戰目錄
- Springboot2.x整合ElasticSearch7.x實戰(一)
- Springboot2.x整合ElasticSearch7.x實戰(二)
- Springboot2.x整合ElasticSearch7.x實戰(三)
??Spring
Spring 學習路線圖:
https://img-blog.csdnimg.cn/20201230220120483.png
-
一篇告訴你什么是Spring
-
第一個Spring程式(代碼篇)
-
手把手整合SSM框架-附原始碼
-
公司這套架構統一處理 try...catch 這么香,求求你不要再滿屏寫了,再發現扣績效!(全域例外處理)
-
CTO 說了,如果發現誰用 kill -9 關閉程式就開除
-
spring的controller是單例還是多例?怎么保證并發的安全
-
真的!@Autowired和@Resource注解別再用錯了!
Spring Boot
SpringBoot最新版常用案例整合,持續更新中 https://github.com/Rodert/SpringBoot-javapub
- SpringBoot快速入門-附原始碼
- Springboot專案的介面防刷
- SpringBoot 中的執行緒池,你真的會用么
- docker 打包 springboot 專案快速入門
- 自定義注解+AOP切面日志+原始碼
- SpringBoot2.x整合Prometheus+Grafana【附原始碼+視頻】
??中間件
zookeeper
- rodert熬夜寫了一份zookeeper總結
RocketMQ
- RocketMq 快速入門教程
Prometheus
- SpringBoot2.x整合Prometheus+Grafana【附原始碼+視頻】
流程引擎
- 老板要我開發一個簡單的作業流引擎
- 手把手實作springboot整合flowable、附原始碼-視頻教程
??Redis
- rodert單排學習redis入門【黑鐵】
- rodert 單排學習 redis 進階【青銅】
- rodert單排學習redis進階【白銀一】
- rodert熬夜寫了一份BloomFilter總結
- 了解Redis過期策略及實作原理
- 快取:熱點key重建優化
- 記一次redis線上問題
- 了解Redis過期策略及實作原理
??Docker
- docker 打包 springboot 專案快速入門
??sql
- 求求你不要再用offset和limit了
- 慢查詢優化方案-SQL篇【JavaPub版】
- 分表分庫解決思路
- 如果mysql磁盤滿了,會發生什么?還真被我遇到了!
??設計模式
- 優雅的替換if-else陳述句
- 單例模式 --- 生產環境怎么用
??分布式
- 分布式唯一ID解決方案-雪花演算法
??shell
- jar包shell啟動腳本
??常用工具
Git
- Git【入門】這一篇就夠了
- 國內加速訪問Github的辦法,超級簡單
- 企業級git組合命令
- 基于 Gitee 搭建個人網站-入門教程
shell
- 代替xshell的國產免費工具
linux
- 史上最全win10下Linux子系統的安裝及優化方案
ffmpeg
- rodert教你學FFmpeg實戰這一篇就夠了
實用工具
- 壓箱底的10款在線工具平臺
- 離線IP地址定位庫
??加密
- FPE格式保留加密
??GoLang
- Java急速轉職GoLang工程師資料-入門篇
??前端
- 網站都變灰色了,1分鐘教你實作
??區塊鏈
- 這破玩意就是區塊鏈?
??web實戰
下載地址: github:https://github.com/Rodert/JavaPub-Web | gitee:https://gitee.com/rodert/JavaPub-Web
- SSM專案合集(公眾號領取)
- 基于SSM圖書館管理系統
- 私活利器 時薪翻一番,推薦幾個SpringBoot專案,建議你改改
- 16K點贊 基于Spring + Vue的前后端分離管理系統ELAdmin,真香
- Spring Boot + Security + MyBatis + Thymeleaf + Activiti 快速開發平臺專案
- 一款基于 Spring Boot 的現代化社區(論壇/問答/社交網路/博客)
- 決定做一個開源專案
??實戰面試
- Java 同學注意!這不是演習
20212021 Java面試題系列教程
- Java基礎--2021面試題系列教程--大白話解讀--JavaPUb版本
- Java容器--2021面試題系列教程(附答案決議)--大白話解讀--JavaPub版本
- Java反射--2021面試題系列教程--大白話解讀--JavaPub版本
《面試1v1》Java面試八股文
《面試1v1》是我在面試中總結和推理出來的,準備在跳槽時溫習回顧使用,
它采用對話的方式、口語化描述技術點,這里沒有花費長篇大論的描述 API 怎么用,主要涉及到的都是高頻面試題、及作業中如何使用,我還穿插了部分原始碼決議,因為現在面試中八股文必不可少,讓文章由淺入深的更好理解,模擬了在真實面試場景中,候選人該如何回答,
迫不及待要看 面試1v1 全集怎么辦? 目前在持續更新中,我一般會先更新到公眾號,提催更
什么是《面試1v1》?
《面試1v1》是一個以對話形式講解知識點的文章合集,是由 JavaPub 撰寫的真人1對1面試對話教程,通過真實案例撰寫,生動、有趣、干貨滿滿,
為什么要寫《面試1v1》這個專題?
我在后臺收到很多讀者的描述,說自己在面試準備程序中感覺抓不住重點,總是復習的沒考、考的沒復習,面試過后導致自己自信心受挫,不知道???♀?該看點什么來,
這里主要以我的經驗給大家一個參照,我們如何在面試中自然的對答,不會因為緊張的忘記,如果用自己的話描述技術難題,避免背課文式的對話,
《面試1v1》有什么用?
文中大多是以實際面試中遇到的情況撰寫,幾乎是大白話式的對話,涉及到的原始碼我也在對話中做了標注,方便我們查閱遺忘的知識點,
最終的目標是幫助大家更好的掌控面試,拿到心儀offer,
《面試1v1》收費嗎,在哪里可以看到全集?
由 JavaPub 完全免費提供,并且持續更新中,在 wx 搜索 JavaPub 就可以直接查看全系列文章,
面試1v1 之后會出第二季嗎?
會的,第二季會從大白話原始碼的角度出發,八股文的朋友不要錯過,
【面試1v1】hashmap
【面試1v1】java注解
【面試1v1】java泛型
【面試1v1】java多執行緒
【面試1v1】CAS
【面試1v1】java反射
【面試1v1】動態代理
【面試1v1】javaNIO
【面試1v1】synchronized
【面試1v1】volatile
【面試1v1】執行緒池
【面試1v1】ThreadLocal
【面試1v1】JVM記憶體模型
【面試1v1】CountDownLatch-CyclicBarrier
【面試1v1】JVM類加載程序
【面試1v1】垃圾回識訓制
原創電子書
鏈接:https://pan.baidu.com/s/1BUjGUevP00GqRw2b0HgBBA?pwd=6e67
提取碼:6e67

看到這里了,點個關注唄!雙擊即可點贊!關注 @JavaPub
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/553938.html
標籤:Java
上一篇:單例模式
下一篇:返回列表
