一線互聯網常見的 14 個 Java 面試題,你顫抖了嗎程序員
1. synchronized 和 reentrantlock 異同
相同點
都實現了多線程同步和內存可見性語義
都是可重入鎖
不同點
實現機制不同 synchronized 通過 java 對象頭鎖標記和 Monitor 對象實現 reentrantlock 通過
synchronized 依賴 jvm 內存模型保證包含共享變量的多線程內存可見性 reentrantlock 通過 ASQ 的
volatile state 保證包含共享變量的多線程內存可見性使用方式不同 synchronized 可以修飾實例方法(鎖住實例對象)、靜態方法(鎖住類對象)、代碼塊(顯示指定鎖對象)reentrantlock 顯示調用 trylock()/lock() 方法,需要在 finally 塊中釋放鎖
功能豐富程度不同 reentrantlock
提供有限時間等候鎖(設置過期時間)、可中斷鎖(lockInterruptibly)、condition(提供 await、signal
不可設置等待時間、不可被中斷(interrupted)
2. concurrenthashmap 為何讀不用加鎖
jdk1.7
1)HashEntry 中的 key、hash、next 均為 final 型,只能表頭插入、刪除結點
2)HashEntry 類的 value 域被聲明為 volatile 型
3)不允許用 null 作為鍵和值,當讀線程讀到某個 HashEntry 的 value 域的值為 null
時,便知道產生了沖突——發生了重排序現象(put 設置新 value 對象的字節碼指令重排序),需要加鎖後重新讀入這個 value 值4)volatile 變量 count 協調讀寫線程之間的內存可見性,寫操作後修改 count,讀操作先讀 count,根據
happen-before 傳遞性原則寫操作的修改讀操作能夠看到
jdk1.8
1)Node 的 val 和 next 均為 volatile 型
2)tabAt 和 casTabAt 對應的 unsafe 操作實現了 volatile 語義
3. ContextClassLoader(線程上下文類加載器)的作用
越過類加載器的雙親委派機制去加載類,如 serviceloader 實現
使用線程上下文類加載器加載類,要註意保證多個需要通信的線程間的類加載器應該是同一個,防止因為不同的類加載器導致類型轉換異常(ClassCastException)
4. tomcat 類加載機制
不同應用使用不同的 webapp 類加載器,實現應用隔離的效果,webapp 類加載器下面是 jsp 類加載器
不同應用共享的 jar 包可以放到 Shared 類加載器 /shared 目錄下
5. osgi 類加載機制
osgi 類加載模型是網狀的,可以在模塊(Bundle)間互相委托
osgi 實現模塊化熱部署的關鍵是自定義類加載器機制的實現,每個 Bundle 都有一個自己的類加載器,當需要更換一個 Bundle時,就把 Bundle 連同類加載器一起換掉以實現代碼的熱替換
當收到類加載請求時,osgi 將按照下面的順序進行類搜索:
1)將以 java.* 開頭的類委派給父類加載器加載
2)否則,將委派列表名單(配置文件 org.osgi.framework.bootdelegation 中定義)內的類委派給父類加載器加載
3)否則,檢查是否在 Import-Package 中聲明,如果是,則委派給 Export 這個類的 Bundle 的類加載器加載
4)否則,檢查是否在 Require-Bundle 中聲明,如果是,則將類加載請求委托給 required bundle 的類加載器
5)否則,查找當前 Bundle 的 ClassPath,使用自己的類加載器加載
6)否則,查找類是否在自己的 Fragment Bundle 中,如果在,則委派給 Fragment Bundle 的類加載器加載
7)否則,查找 Dynamic Import-Package(Dynamic Import 只有在真正用到此 Package
的時候才進行加載)的 Bundle,委派給對應 Bundle 的類加載器加載8)否則,類查找失敗
6. 如何結束一個一直運行的線程
使用退出標誌,這個 flag 變量要多線程可見
使用 interrupt,結合 isInterrupted() 使用
7. threadlocal 使用場景及問題
threadlocal 並不能解決多線程共享變量的問題,同一個 threadlocal 所包含的對象,在不同的 thread
中有不同的副本,互不幹擾用於存放線程上下文變量,方便同一線程對變量的前後多次讀取,如事務、數據庫 connection 連接,在 web 編程中使用的更多
問題: 註意線程池場景使用 threadlocal,因為實際變量值存放在了 thread 的 threadlocalmap
類型變量中,如果該值沒有 remove,也沒有先 set 的話,可能會得到以前的舊值問題: 註意線程池場景下的內存泄露,雖然 threadlocal 的 get/set 會清除 key(key 為 threadlocal的弱引用,value 是強引用,導致 value 不釋放)為 null 的 entry,但是最好 remove
8. 線程池從啟動到工作的流程
剛創建時,裏面沒有線程
調用 execute() 添加任務時:
1)如果正在運行的線程數量小於核心參數 corePoolSize,繼續創建線程運行這個任務
2)否則,如果正在運行的線程數量大於或等於 corePoolSize,將任務加入到阻塞隊列中
3)否則,如果隊列已滿,同時正在運行的線程數量小於核心參數 maximumPoolSize,繼續創建線程運行這個任務
4)否則,如果隊列已滿,同時正在運行的線程數量大於或等於 maximumPoolSize,根據設置的拒絕策略處理
5)完成一個任務,繼續取下一個任務處理
6)沒有任務繼續處理,線程被中斷或者線程池被關閉時,線程退出執行,如果線程池被關閉,線程結束
7)否則,判斷線程池正在運行的線程數量是否大於核心線程數,如果是,線程結束,否則線程阻塞。因此線程池任務全部執行完成後,繼續留存的線程池大小為corePoolSize
8)本文所列出的 14 個 Java面試題只是我所遭遇的面試中的一部分,其他的面試題我也會陸續整理出來,說到這裏另外順便給大家推薦一個架構交流學習群:650385180,裏面會分享一些資深架構師錄制的視頻錄像:有Spring,MyBatis,Netty 源碼分析,高並發、高性能、分布式、微服務架構的原理,JVM性能優化這些成為架構師必備的知識體系。還能領取免費的學習資源,相信對於已經工作和遇到技術瓶頸的碼友,在這個群裏會有你需要的內容。
9. 阻塞隊列 BlockingQueue take 和 poll 區別
poll(time):取走 BlockingQueue 裏排在首位的對象, 若不能立即取出,則可以等 time參數規定的時間,取不到時返回 null
take():取走 BlockingQueue 裏排在首位的對象,若 BlockingQueue 為空,阻塞直到BlockingQueue 有新的對象被加入
10. 如何從 FutureTask 不阻塞獲取結果
get(long timeout,TimeUnit unit),超時則返回
輪詢,先通過 isDone()判斷是否結束,然後調用 get()
11. blockingqueue 如果存放了比較關鍵的數據,系統宕機該如何處理
開放性問題,歡迎討論
將隊列持久化,比較麻煩,需要將生產數據持久化到磁盤,持久化成功才返回,消費者線程從磁盤加載數據到內存阻塞隊列中,維護消費offset,啟動時,根據消費 offset 從磁盤加載數據
加入消息隊列,保證消息不丟失,生成序列號,消費冪等,根據消費進程決定系統重啟後的生產狀態
12. NIO 與傳統 I/O 的區別
節約線程,NIO 由原來的每個線程都需要阻塞讀寫變成了由單線程(即 Selector)負責處理多個 channel
註冊(register)的興趣事件(SelectionKey)集合(底層借助操作系統提供的 epoll()),netty bossgroup 處理 accept 連接(沒看明白為什麽 bossgroup 設置多個 thread的必要性),workergroup 處理具體業務流程和數據讀寫NIO 提供非阻塞操作
傳統 I/O 以流的方式處理數據,而 NIO 以塊的方式處理數據,NIO 提供 bytebuffer,分為堆內和堆外緩沖區,讀寫時均先放到該緩沖區中,然後由內核通過 channel傳輸到對端,堆外緩沖區不走內核,提升了性能
13. list 中存放可重復字符串,如何刪除某個字符串
調用 iterator 相關方法刪除
倒刪,防止正序刪除導致的數組重排,index 跳過數組元素問題
14. 有哪些 GC ROOTS(跟日常開發比較相關的是和此相關的內存泄露)
所有 Java 線程當前活躍的棧幀裏指向 GC 堆裏的對象的引用,因此用不到的對象及時置 null,提升內存回收效率
靜態變量引用的對象,因此減少靜態變量特別是靜態集合變量的大小,集合存放的對象覆寫 euqls()和 hashcode(),防止持續增長
本地方法 JNI 引用的對象
方法區中的常量引用的對象,因此減少在長字符串上調用 String.intern()
classloader 加載的 class 對象,因此自定義 classloader 無效時及時置 null並且註意類加載器加載對象之間的隔離
jvm 裏的一些靜態數據結構裏指向 GC 堆裏的對象的引用
…
一線互聯網常見的 14 個 Java 面試題,你顫抖了嗎程序員