文章最后附帶有電子書下載地址。
我是 javapub,一名 Markdown
程序員從?????,八股文種子選手。
面試官: 你好,我看到你的簡歷上寫著你熟悉 Java 中的 "synchronized" 關鍵字。你能給我講講它的作用嗎?
候選人: 當然,"synchronized" 是 Java 中的一個關鍵字,用于實現(xiàn)同步機制。它可以用來修飾方法或代碼塊,以確保在同一時間只有一個線程可以訪問被修飾的代碼。
面試官: 很好。那么,你能舉個例子來說明 "synchronized" 關鍵字的使用方法嗎?
候選人: 當然。你可以使用 "synchronized" 關鍵字來修飾方法或代碼塊。例如,你可以這樣使用:
public synchronized void doSomething() { // ... }
在上面的代碼中,"synchronized" 關鍵字修飾了 "doSomething()" 方法。這意味著在同一時間只有一個線程可以訪問該方法。
面試官: 很好。那么,如果我想修飾一個代碼塊,應該怎么做呢?
候選人: 你可以這樣使用 "synchronized" 關鍵字來修飾一個代碼塊:
public void doSomething() { synchronized (this) { // ... } }
在上面的代碼中,"synchronized" 關鍵字修飾了一個代碼塊,該代碼塊使用 "this" 作為鎖對象。這意味著在同一時間只有一個線程可以訪問該代碼塊。
面試官: 很好。那么,你能解釋一下 "synchronized" 關鍵字的實現(xiàn)原理嗎?
候選人: 當一個線程訪問一個被 "synchronized" 關鍵字修飾的方法或代碼塊時,它會嘗試獲取該對象的監(jiān)視器鎖。如果該鎖已經(jīng)被其他線程持有,則該線程將被阻塞,直到該鎖被釋放。下面是一個使用 "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" 包中的并發(fā)集合類,例如 ConcurrentHashMap、CopyOnWriteArrayList 等,這些類使用了更高效的同步機制,可以避免 "synchronized" 關鍵字帶來的性能開銷。
面試官: 很好,你的回答很不錯。那么,你能告訴我 "synchronized" 關鍵字和 "Lock" 接口之間的區(qū)別嗎?
候選人: 當然。 "synchronized" 關鍵字是 Java 中內置的同步機制,它可以用來修飾方法或代碼塊,使用起來比較簡單,但是它的性能開銷比較大。而 "Lock" 接口是 Java 中提供的一種更加靈活的同步機制,它可以實現(xiàn)更細粒度的鎖控制,例如可重入鎖、讀寫鎖等,使用起來比較復雜,但是它的性能開銷比較小。
面試官: 很好,你的回答很清晰。那么,你有沒有使用過 "Lock" 接口呢?
候選人: 是的,我有使用過 "Lock" 接口。例如,我曾經(jīng)使用過 ReentrantLock 類來實現(xiàn)可重入鎖,這可以避免 "synchronized" 關鍵字的性能開銷,并且可以實現(xiàn)更細粒度的鎖控制。
面試官: 很好,你的經(jīng)驗很豐富。那么,你能告訴我 "Lock" 接口的一些特點嗎?
候選人: 當然。 "Lock" 接口的一些特點包括:
可以實現(xiàn)更細粒度的鎖控制,例如可重入鎖、讀寫鎖等。
可以實現(xiàn)公平鎖和非公平鎖。
可以實現(xiàn)超時鎖和可中斷鎖。
可以實現(xiàn)多個條件變量,可以更加靈活地控制線程的等待和喚醒。
面試官: 那么,你能告訴我 "synchronized" 關鍵字和 "volatile" 關鍵字之間的區(qū)別嗎?
候選人: 當然。 "synchronized" 關鍵字和 "volatile" 關鍵字都可以用來實現(xiàn)多線程之間的同步,但是它們的作用不同。 "synchronized" 關鍵字可以確保在同一時間只有一個線程可以訪問被修飾的代碼,而 "volatile" 關鍵字可以確保變量的可見性,即當一個線程修改了變量的值后,其他線程可以立即看到這個修改。
面試官: 看來你使用的很好,下面問一點深入的東西?;卮鸩簧蟻硪矝]關系,可以自己想想。
面試官: 好的,那么你能夠從 "synchronized" 的底層 Java 實現(xiàn)角度,解釋一下它的實現(xiàn)原理嗎?
候選人: 當一個線程訪問一個被 "synchronized" 關鍵字修飾的方法或代碼塊時,它會嘗試獲取該對象的監(jiān)視器鎖。如果該鎖已經(jīng)被其他線程持有,則該線程將被阻塞,直到該鎖被釋放。在 Java 中,每個對象都有一個監(jiān)視器鎖,也稱為內部鎖或互斥鎖。當一個線程獲取了一個對象的監(jiān)視器鎖后,其他線程就無法訪問該對象的被 "synchronized" 關鍵字修飾的方法或代碼塊,直到該鎖被釋放。
在 Java 中,"synchronized" 關鍵字的實現(xiàn)是基于對象頭中的標記字。當一個對象被鎖定時,它的標記字會被設置為鎖定狀態(tài),當鎖被釋放時,標記字會被清除。在 Java 6 及之前的版本中,對象頭中的標記字是 32 位的,其中 25 位用于存儲對象的哈希碼,4 位用于存儲對象的分代年齡,2 位用于存儲鎖標志位,1 位用于存儲是否是偏向鎖。在 Java 7 及之后的版本中,對象頭中的標記字被重新設計,其中 32 位用于存儲對象的哈希碼和分代年齡,而鎖標志位則被存儲在一個單獨的數(shù)據(jù)結構中。
面試官: 很好,你的回答很詳細。那么,你能夠給我講講 "synchronized" 關鍵字的優(yōu)化策略嗎?
候選人: 當然。在 Java 中,"synchronized" 關鍵字的性能開銷比較大,因為每個線程都需要獲取鎖才能訪問被修飾的代碼。為了優(yōu)化 "synchronized" 關鍵字的性能,Java 6 及之后的版本中引入了偏向鎖、輕量級鎖和重量級鎖等優(yōu)化策略。
偏向鎖是一種針對單線程訪問同步塊的優(yōu)化策略。當一個線程訪問一個被 "synchronized" 關鍵字修飾的代碼塊時,它會嘗試獲取該對象的偏向鎖。如果該鎖沒有被其他線程持有,則該線程可以直接獲取該鎖,而無需進行同步操作。如果該鎖已經(jīng)被其他線程持有,則該線程會嘗試升級為輕量級鎖或重量級鎖。
輕量級鎖是一種針對多線程訪問同步塊的優(yōu)化策略。當一個線程訪問一個被 "synchronized" 關鍵字修飾的代碼塊時,它會嘗試獲取該對象的輕量級鎖。如果該鎖沒有被其他線程持有,則該線程可以直接獲取該鎖,而無需進行同步操作。如果該鎖已經(jīng)被其他線程持有,則該線程會嘗試自旋等待該鎖的釋放。
重量級鎖是一種針對多線程訪問同步塊的默認策略。當一個線程訪問一個被 "synchronized" 關鍵字修飾的代碼塊時,它會嘗試獲取該對象的重量級鎖。如果該鎖沒有被其他線程持有,則該線程可以直接獲取該鎖,而無需進行同步操作。如果該鎖已經(jīng)被其他線程持有,則該線程會被阻塞,直到該鎖被釋放。
面試官: 很好,你的回答很詳細。那么,你能夠給我講講 "synchronized" 關鍵字的底層 Java 源碼實現(xiàn)嗎?
候選人: 當然。在 Java 中,"synchronized" 關鍵字的底層實現(xiàn)是通過 monitorenter 和 monitorexit 指令來實現(xiàn)的。當一個線程訪問一個被 "synchronized" 關鍵字修飾的方法或代碼塊時,它會嘗試獲取該對象的監(jiān)視器鎖,這可以通過 monitorenter 指令來實現(xiàn)。當該線程執(zhí)行完被 "synchronized" 關鍵字修飾的方法或代碼塊后,它會釋放該對象的監(jiān)視器鎖,這可以通過 monitorexit 指令來實現(xiàn)。
參考底層指令:
以下是 JVM 中與 "synchronized" 相關的源碼:
monitorenter 指令的實現(xiàn):
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 指令的實現(xiàn)是通過獲取對象的鎖來實現(xiàn)的。如果該鎖沒有被其他線程持有,則該線程可以直接獲取該鎖,而無需進行同步操作。如果該鎖已經(jīng)被其他線程持有,則該線程會嘗試升級為輕量級鎖或重量級鎖。
monitorexit 指令的實現(xiàn):
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 指令的實現(xiàn)是通過釋放對象的鎖來實現(xiàn)的。如果該鎖被當前線程持有,則該線程可以直接釋放該鎖,而無需進行同步操作。如果該鎖被其他線程持有,則該線程會被阻塞,直到該鎖被釋放。
ObjectMonitor 類的實現(xiàn):
class ObjectMonitor : public CHeapObj<mtSynchronizer> { friend class VMStructs; private: volatile intptr_t _header; // 對象頭,用于存儲鎖狀態(tài)和其他信息 volatile intptr_t _count; // 計數(shù)器,用于記錄重入次數(shù) volatile intptr_t _waiters; // 等待隊列長度,用于記錄等待鎖的線程數(shù) volatile intptr_t _recursions; // 遞歸深度,用于記錄當前線程已經(jīng)獲取鎖的次數(shù) volatile intptr_t _object; // 對象指針,指向被鎖定的對象 volatile intptr_t _owner; // 持有者指針,指向當前持有鎖的線程 volatile intptr_t _WaitSet; // 等待隊列頭指針,指向等待隊列的頭節(jié)點 volatile intptr_t _EntryList; // 等待隊列尾指針,指向等待隊列的尾節(jié)點 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; // 自旋持續(xù)時間,用于控制自旋等待的時間 volatile intptr_t _SpinEarly; // 自旋提前量,用于控制自旋等待的時間 volatile intptr_t _contentions; // 競爭次數(shù),用于記錄獲取鎖的競爭次數(shù) volatile intptr_t _succ; // 成功次數(shù),用于記錄獲取鎖的成功次數(shù) volatile intptr_t _cxqWaitTime; // 條件變量等待時間,用于記錄條件變量等待的時間 volatile intptr_t _reserved; // 保留字段,用于未來擴展 static int _header_offset; // 對象頭偏移量,用于訪問對象頭中的信息 static int _count_offset; // 計數(shù)器偏移量,用于訪問計數(shù)器中的信息 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; // 自旋持續(xù)時間偏移量,用于訪問自旋持續(xù)時間中的信息 static int _SpinEarly_offset; // 自旋提前量偏移量,用于訪問自旋提前量中的信息 static int _contentions_offset; // 競爭次數(shù)偏移量,用于訪問競爭次數(shù)中的信息 static int _succ_offset; // 成功次數(shù)偏移量,用于訪問成功次數(shù)中的信息 static int _cxqWaitTime_offset; // 條件變量等待時間偏移量,用于訪問條件變量等待時間中的信息 static int _reserved_offset; // 保留字段偏移量,用于訪問保留字段中的信息 ... };
在上面的代碼中,ObjectMonitor 類是 JVM 中與 "synchronized" 相關的核心類之一。它包含了對象的監(jiān)視器鎖的狀態(tài)信息,例如鎖的持有者、等待隊列、遞歸深度等。在 Java 中,每個對象都有一個 ObjectMonitor 對象與之對應,用于實現(xiàn) "synchronized" 關鍵字的同步機制。
面試官: 很好,你的回答很全面,你已進入候補名單。有消息會通知你。
候選人: 源碼都背下來了,你給我看這。
最近我在更新《面試1v1》系列文章,主要以場景化的方式,講解我們在面試中遇到的問題,致力于讓每一位工程師拿到自己心儀的offer,感興趣可以關注JavaPub追更!
??目錄合集:
Gitee:https://gitee.com/rodert/JavaPub
GitHub:https://github.com/Rodert/JavaPub
http://javapub.net.cn
文章列表
??最少必要面試題
Java基礎
Java并發(fā)入門
Java容器
JavaWeb
JVM
MySQL
MyBatis
Spring
SpringBoot
Redis
ElasticSearch
[Kafka]
Zookeeper
Docker
緩存
??知識點總結
下面是原創(chuàng)PDF干貨版,持續(xù)更新中。
51頁的MyBatis
14頁的zookeeper總結
...
??Java基礎
鎖
volatile關鍵字的作用
jdk8
原來ThreadLocal的Lambda構造方式這么簡單
??數(shù)據(jù)結構與算法
冒泡排序就是這么容易
選擇排序就是這么容易
插入排序就是這么容易
希爾排序就是這么容易
歸并排序就是這么容易
快速排序就是這么容易
堆排序就是這么容易
計數(shù)排序就是這么容易
桶排序就是這么容易
基數(shù)排序就是這么容易
rodert熬夜寫了一份BloomFilter總結
哈希算法篇 - 布隆過濾器
B樹和B+樹的區(qū)別
??Mybatis
rodert熬夜寫了一份Mybatis總結
MyBatis SQL 批量更新(代碼+案例)
??搜索
Lucene
Lucene就是這么容易
Elasticsearch
Springboot2.x整合ElasticSearch7.x實戰(zhàn)目錄
Springboot2.x整合ElasticSearch7.x實戰(zhàn)(一)
Springboot2.x整合ElasticSearch7.x實戰(zhàn)(二)
Springboot2.x整合ElasticSearch7.x實戰(zhàn)(三)
??Spring
Spring 學習路線圖:
一篇告訴你什么是Spring
第一個Spring程序(代碼篇)
手把手整合SSM框架-附源碼
公司這套架構統(tǒng)一處理 try...catch 這么香,求求你不要再滿屏寫了,再發(fā)現(xiàn)扣績效!(全局異常處理)
CTO 說了,如果發(fā)現(xiàn)誰用 kill -9 關閉程序就開除
spring的controller是單例還是多例?怎么保證并發(fā)的安全
真的!@Autowired和@Resource注解別再用錯了!
Spring Boot
SpringBoot最新版常用案例整合,持續(xù)更新中 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【附源碼+視頻】
流程引擎
老板要我開發(fā)一個簡單的工作流引擎
手把手實現(xiàn)springboot整合flowable、附源碼-視頻教程
??Redis
rodert單排學習redis入門【黑鐵】
rodert 單排學習 redis 進階【青銅】
rodert單排學習redis進階【白銀一】
rodert熬夜寫了一份BloomFilter總結
了解Redis過期策略及實現(xiàn)原理
緩存:熱點key重建優(yōu)化
記一次redis線上問題
了解Redis過期策略及實現(xiàn)原理
??Docker
docker 打包 springboot 項目快速入門
??sql
求求你不要再用offset和limit了
慢查詢優(yōu)化方案-SQL篇【JavaPub版】
分表分庫解決思路
如果mysql磁盤滿了,會發(fā)生什么?還真被我遇到了!
??設計模式
優(yōu)雅的替換if-else語句
單例模式 --- 生產(chǎn)環(huán)境怎么用
??分布式
分布式唯一ID解決方案-雪花算法
??shell
jar包shell啟動腳本
??常用工具
Git
Git【入門】這一篇就夠了
國內加速訪問Github的辦法,超級簡單
企業(yè)級git組合命令
基于 Gitee 搭建個人網(wǎng)站-入門教程
shell
代替xshell的國產(chǎn)免費工具
linux
史上最全win10下Linux子系統(tǒng)的安裝及優(yōu)化方案
ffmpeg
rodert教你學FFmpeg實戰(zhàn)這一篇就夠了
實用工具
壓箱底的10款在線工具平臺
離線IP地址定位庫
??加密
FPE格式保留加密
??GoLang
Java急速轉職GoLang工程師資料-入門篇
??前端
網(wǎng)站都變灰色了,1分鐘教你實現(xiàn)
??區(qū)塊鏈
這破玩意就是區(qū)塊鏈?
??web實戰(zhàn)
下載地址: github:https://github.com/Rodert/JavaPub-Web | gitee:https://gitee.com/rodert/JavaPub-Web
SSM項目合集(公眾號領?。?/p>
基于SSM圖書館管理系統(tǒng)
私活利器 時薪翻一番,推薦幾個SpringBoot項目,建議你改改
16K點贊 基于Spring + Vue的前后端分離管理系統(tǒng)ELAdmin,真香
Spring Boot + Security + MyBatis + Thymeleaf + Activiti 快速開發(fā)平臺項目
一款基于 Spring Boot 的現(xiàn)代化社區(qū)(論壇/問答/社交網(wǎng)絡/博客)
決定做一個開源項目
??實戰(zhàn)面試
Java 同學注意!這不是演習
20212021 Java面試題系列教程
Java基礎--2021面試題系列教程--大白話解讀--JavaPUb版本
Java容器--2021面試題系列教程(附答案解析)--大白話解讀--JavaPub版本
Java反射--2021面試題系列教程--大白話解讀--JavaPub版本
《面試1v1》Java面試八股文
《面試1v1》是我在面試中總結和推理出來的,準備在跳槽時溫習回顧使用。
它采用對話的方式、口語化描述技術點,這里沒有花費長篇大論的描述 API 怎么用,主要涉及到的都是高頻面試題、及工作中如何使用,我還穿插了部分源碼解析,因為現(xiàn)在面試中八股文必不可少,讓文章由淺入深的更好理解。模擬了在真實面試場景中,候選人該如何回答。
迫不及待要看 面試1v1 全集怎么辦? 目前在持續(xù)更新中,我一般會先更新到公眾號,提催更
什么是《面試1v1》?
《面試1v1》是一個以對話形式講解知識點的文章合集,是由 JavaPub 編寫的真人1對1面試對話教程,通過真實案例編寫,生動、有趣、干貨滿滿。
為什么要寫《面試1v1》這個專題?
我在后臺收到很多讀者的描述,說自己在面試準備過程中感覺抓不住重點,總是復習的沒考、考的沒復習。面試過后導致自己自信心受挫,不知道???♀?該看點什么來。
這里主要以我的經(jīng)驗給大家一個參照,我們如何在面試中自然的對答,不會因為緊張的忘記。如果用自己的話描述技術難題,避免背課文式的對話。
《面試1v1》有什么用?
文中大多是以實際面試中遇到的情況編寫,幾乎是大白話式的對話。涉及到的源碼我也在對話中做了標注,方便我們查閱遺忘的知識點。
最終的目標是幫助大家更好的掌控面試,拿到心儀offer。
《面試1v1》收費嗎,在哪里可以看到全集?
由 JavaPub 完全免費提供,并且持續(xù)更新中,在 wx 搜索 JavaPub 就可以直接查看全系列文章。
面試1v1 之后會出第二季嗎?
會的,第二季會從大白話源碼的角度出發(fā),八股文的朋友不要錯過。
原創(chuàng)電子書
鏈接:https://pan.baidu.com/s/1b8rTprlpoVvlzKD7y3y9rw?pwd=jx4dbr/>提取碼:jx4d文章來源:http://www.zghlxwxcb.cn/news/detail-466244.html
看到這里了,點個關注唄!雙擊即可點贊!關注 @JavaPub文章來源地址http://www.zghlxwxcb.cn/news/detail-466244.html
到了這里,關于Java 八股文面試過程系列之synchronized關鍵字的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!