標籤:tcl display export 服務架構 重啟 序號 自訂 oss oar
跳槽不算頻繁,但參加過不少面試(電話面試、face to face 面試),面過大 / 小公司、互連網 / 傳統軟體公司,麵糊過(眼高手低,缺乏實戰經驗,掛掉),也面過人,所幸未因失敗而氣餒,在此過程中不斷查缺補漏,養成了踏實、追本溯源、持續改進的習慣,特此將自己經曆過、構思過的一些面試題記錄下來,如果答案有問題,歡迎拍磚討論,希望能對找工作或者感興趣的同學有所協助,陸續整理中。
1. synchronized 和 reentrantlock 異同
相同點
都實現了多線程同步和記憶體可見度語義
都是可重新進入鎖
不同點
實現機制不同 synchronized 通過 java 對象頭鎖標記和 Monitor 對象實現 reentrantlock 通過
CAS、ASQ(AbstractQueuedSynchronizer)和 locksupport(用於阻塞和解除阻塞)實現
synchronized 依賴 jvm 記憶體模型保證包含共用變數的多線程記憶體可見度 reentrantlock 通過 ASQ 的
volatile state 保證包含共用變數的多線程記憶體可見度
使用方式不同 synchronized 可以修飾執行個體方法(鎖住執行個體對象)、靜態方法(鎖住類對象)、代碼塊(顯示指定鎖對象)reentrantlock 顯示調用 trylock()/lock() 方法,需要在 finally 塊中釋放鎖
功能豐富程度不同 reentrantlock
提供有限時間等候鎖(設定到期時間)、可中斷鎖(lockInterruptibly)、condition(提供 await、signal
等方法)等豐富語義 reentrantlock 提供公平鎖和非公平鎖實現 synchronized
不可設定等待時間、不可被中斷(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
3. ContextClassLoader(線程上下文類載入器)的作用
4. tomcat 類載入機制
5. osgi 類載入機制
當收到類載入請求時,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. 如何結束一個一直啟動並執行線程
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 不阻塞擷取結果
11. blockingqueue 如果存放了比較關鍵的資料,系統宕機該如何處理
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 中存放可重複字串,如何刪除某個字串
14. 有哪些 GC ROOTS(跟日常開發比較相關的是和此相關的記憶體泄露)
所有 Java 線程當前活躍的棧幀裡指向 GC 堆裡的對象的引用,因此用不到的對象及時置 null,提升記憶體回收效率
靜態變數引用的對象,因此減少靜態變數特別是靜態集合變數的大小,集合存放的對象覆寫 euqls()和 hashcode(),防止持續增長
本地方法 JNI 引用的對象
方法區中的常量引用的對象,因此減少在長字串上調用 String.intern()
classloader 載入的 class 對象,因此自訂 classloader 無效時及時置 null並且注意類載入器載入對象之間的隔離
jvm 裡的一些待用資料結構裡指向 GC 堆裡的對象的引用
…
一線互連網常見的 14 個 Java 面試題,你顫抖了嗎程式員