JavaRush /Java Blog /Random-TW /翻譯:按主題排列的前 50 個面試問題。第2部分。
KapChook
等級 19
Volga

翻譯:按主題排列的前 50 個面試問題。第2部分。

在 Random-TW 群組發布
原文第二部分翻譯為新手、經驗豐富的程式設計師的 Top 50 Java 執行緒面試問題答案。 第一部分。
  1. 如何檢查線程是否持有鎖?

  2. 我不知道你可以檢查線程目前是否持有鎖,直到我在電話採訪中遇到這個問題。java.lang.Thread有一個holdsLock()方法,當且僅噹噹前執行緒持有特定物件的監視器時,它會傳回true。
  3. 如何獲取線程轉儲?

  4. 線程轉儲可讓您找出線程當前正在做什麼。有多種方法可以獲取線程轉儲,具體取決於作業系統。在 Windows 上,您可以使用 ctrl + Break 組合,在 Linux 上,您可以使用kill -3 指令。您也可以使用 jstack 公用程式;它對進程 ID 進行操作,您可以使用另一個 jps 公用程式找到該進程 ID。
  5. 什麼 JVM 參數用來控制執行緒的堆疊大小?

  6. 這是簡單的 -Xss 參數之一,用於控制 Java 中線程堆疊的大小。
  7. 同步鎖和可重入鎖的差別?

  8. 有時,實現互斥的唯一方法是透過synchronized關鍵字,但它有幾個缺點,例如無法將鎖定擴展到方法或程式碼區塊之外,等等。Java 5 透過 Lock 介面提供更細粒度的控制來解決這個問題。ReentrantLock 是一種常見的 Lock 實現,它為 Lock 提供與隱式監視器相同的基本行為和語義,使用同步方法實現,但具有增強的功能。
  9. 給定 3 個線程 T1、T2 和 T3?如何實現序列T1、T2、T3?

  10. 可以透過多種方式實現一致性,但您可以簡單地使用 join() 方法在另一個執行緒完成執行時啟動一個執行緒。要實作給定的序列,需要先啟動最後一個線程,然後以相反的順序呼叫 join() 方法,即 T3 呼叫 T2.join,T2 呼叫 T1.join,因此 T1 先完成,T3 最後完成。
  11. 收益率法有什麼作用?

  12. Yield 方法是要求執行緒放棄 CPU 以便另一個執行緒可以執行的一種方法。這是一個靜態方法,它只保證當前執行緒讓出處理器,但不決定去哪個執行緒執行。
  13. ConcurrentHashMap的並發等級是多少?

  14. ConcurrentHashMap 透過將實際映射分成多個部分來實現其可擴展性和線程安全性。這種分離是透過使用一定程度的並行性來實現的。這是 ConcurrentHashMap 建構函數的可選參數,其預設值為 16。
  15. 什麼是信號量?

  16. 信號量是一種新型的同步器。這是一個帶有計數器的信號量。從概念上講,信號量控制一組權限。如有必要,每個 acquire() 在權限可用之前都會阻塞,然後取得它。每個release()都會增加一個權限,可能會釋放阻塞的獲取者。然而,這並沒有使用實際的權限物件;信號量只是儲存可用信號量的數量並採取相應的行動。信號量用於保護數量有限的昂貴資源,例如到池資料庫的連線。
  17. 如果執行緒池佇列已滿並且您提交任務會發生什麼情況?

  18. 如果執行緒池佇列已滿,則提交的任務將被「拒絕」。ThreadPoolExecutor的submit()方法拋出RejectedExecutionException,之後呼叫RejectedExecutionHandler。
  19. 執行緒池上的submit()和execute()方法之間的差異?

  20. 這兩種方法都是向執行緒池提交任務的方法,但是它們之間有細微的差異。Execute(Runnable command) 定義在 Executor 介面中,並在將來執行給定的任務,但更重要的是,不返回任何內容。另一方面,submit() 是一個重載方法,它可以接受 Runnable 和 Callable 任務,並且可以傳回一個 Future 對象,該物件可用於取消執行和/或等待計算結果。此方法定義在ExecutorService介面中,該介面繼承自Executor接口,每個線程池類,如ThreadPoolExecutor或ScheduledThreadPoolExecutor都繼承了這些方法。
  21. 什麼是阻塞方法?

  22. 阻塞方法是阻塞直到任務完成的方法,例如ServerSocketaccept()方法在等待客戶端連線時阻塞。這裡,阻塞意味著在作業完成之前控制不會返回呼叫方法。另一方面,有一些非同步或非阻塞方法在任務完成之前完成。
  23. Swing 線程安全嗎?

  24. 簡單地說,不,Swing 不是線程安全的,但是你需要解釋你的意思,即使面試官沒有問。當我們說Swing不是線程安全的時候,我們通常指的是它是一個不能被多線程修改的元件。對 GUI 元件的所有變更都必須在 AWT 執行緒中進行,Swing 提供了同步和非同步方法來調度此類變更。
  25. invokeAndWait 和 invokeLater 之間的差異?

  26. 這兩個 Swing API 方法允許開發人員從執行緒而不是從事件管理器執行緒更新 GUI 元件。InvokeAndWait() 同步更新 GUI 元件,例如進度條;每次取得進度時,必須更新進度條以反映變更。如果在另一個執行緒中追蹤進度,則必須呼叫 invokeAndWait() 來指派事件調度程式執行緒來更新該元件。而invokeLater()是更新元件的非同步呼叫。
  27. 哪些 Swing API 方法是線程安全的?

  28. 這個問題又是關於Swing和線程安全的,雖然Swing元件不是線程安全的,但是有一些方法可以從多個線程安全地呼叫。我知道 repaint() 和 revalidate() 是線程安全的,但是不同的 Swing 元件上還有其他方法,例如 JTextComponent 的 setText() 和 JTextArea 的 insert() 和 append() 方法。
  29. 如何建立不可變物件?

  30. 這個問題看似與多執行緒和並發無關,但其實確實如此。不變性有助於簡化已經複雜的平行程式碼。不可變物件對於開發人員來說非常昂貴,因為它可以在沒有任何同步的情況下進行傳播。不幸的是,Java沒有@Immutable註解,這將使你的物件不可變,為此開發人員需要努力工作。要建立不可變對象,您需要遵循一些基礎知識:在構造函數中進行初始化、沒有 setter、沒有引用洩漏、儲存可變對象的單獨副本。
  31. 什麼是讀寫鎖?

  32. 一般來說,ReadWriteLock 是鎖定解析技術的結果,旨在提高平行應用程式的效能。這是Java 5中新增的介面。它操作一對相關的鎖,一個用於讀取操作,一個用於寫入操作。讀取器鎖可以由多個讀取執行緒同時持有,直到沒有寫入器為止。寫鎖是獨佔的。如果需要,您可以使用規則集實作一個接口,也可以使用 ReentrantReadWriteLock,它最多支援 65535 個遞歸寫鎖和 65535 個讀鎖。
  33. 什麼是忙旋轉?

  34. Busy Spin 是程式設計師用來強制執行緒在特定條件下等待的一種技術。與涉及放棄處理器控制的傳統方法 wait()、sleep() 或 Yield() 不同,此方法不會放棄處理器;相反,它只是執行一個空循環。為什麼有人會這樣做?保存處理器快取。在多核心系統上,掛起的執行緒可能會繼續在另一個核心上執行,這意味著快取重建。為了避免代價高昂的重建,程式設計師更喜歡透過使用繁忙自旋來減少等待。
  35. 易失性變數和原子變數之間的區別?

  36. 這是一個相當有趣的問題,乍一看,揮發性變數和原子變數看起來很相似,但它們仍然不同。Volatile 變數提供了發生在先前的保證,即寫入將在任何後續寫入之前發生;它不保證原子性。例如,count++操作不會僅僅因為count被聲明為揮發性而成為原子操作。另一方面,AtomicInteger 類別提供了一個原子方法來原子地執行此類複雜操作,例如 getAndIncrement() 是增量運算子的原子替代,它可用於以原子方式將目前值加一。其他資料型別也有原子版本。
  37. 如果執行緒在同步區塊中拋出異常會發生什麼?

  38. 對於普通 Java 程式設計師來說,這是另一個棘手的問題。無論您如何退出同步區塊,無論是正常地完成執行還是突然拋出異常,執行緒在進入同步區塊時都會釋放所取得的鎖定。這就是為什麼我喜歡同步鎖塊而不是釋放鎖時需要特別小心的介面的原因之一,通常透過在finally塊中釋放鎖來實現。
  39. 什麼是 Singleton 的雙重檢查鎖定?

  40. 這是最常見的面試問題之一,儘管它很受歡迎,但候選人回答它的機會最多只有 50%。他們一半的時間無法編寫程式碼,另一半的時間則無法解釋 Java 1.5 中的程式碼是如何被破壞和修復的。這是創建線程安全單例的舊方法,它試圖通過僅在首次實例化單例實例時阻塞來優化性能,但由於其複雜性以及它在 JDK 1.4 中被破壞的事實,我個人不喜歡它。儘管如此,即使您不喜歡這種方法,從面試的角度了解它也是有用的。
  41. 如何建立線程安全的單例?

  42. 這個問題是上一個問題的補充。如果你說你不喜歡雙重檢查鎖定,那麼面試官將被迫詢問創建線程安全單例的替代方法。而且它們是,您可以利用類別載入和靜態變數初始化功能來實例化 Singleton,也可以利用強大的枚舉類型。
  43. 列出您在平行程式設計中遵循的 3 個習慣?

  44. 這是我最喜歡的問題,因為我相信編寫並行程式碼時需要遵循某些規則,這有助於提高效能、調試和支援。以下是我認為每個 Java 程式設計師都應該遵循的 3 條最佳規則:
    • 始終為您的線程指定有意義的名稱
    • 在平行程式碼中尋找錯誤或追蹤異常是一項相當困難的任務。OrderProcessor、QuoteProcessor 或 TradeProcessor 比 Thread-1 好得多。線程 2 和線程 3。該名稱應反映執行緒執行的任務。所有主流框架甚至JDK都遵循這個規則。
    • 避免阻塞或縮小同步範圍
    • 阻塞的成本很高,而上下文切換的成本則更高。盡量避免同步和阻塞,這樣您就可以將臨界區減少到所需的最低限度。這就是為什麼我更喜歡定時阻止而不是定時方法,因為它可以讓您對阻止的程度進行絕對控制。
    • 在同步器和等待和通知之間,選擇同步器
    • 首先,CountDownLatch、Semaphore、CyclicBarrier 或 Exchanger 等同步器簡化了編碼。使用wait和notify來實現複雜的控制流程是非常困難的。其次,這些類別是由業內最優秀的人員編寫和維護的,並且它們很有可能在未來的 JDK 版本中被優化或替換為更好的程式碼。透過使用高級同步實用程序,您將自動獲得所有這些好處。
    • 在並發收集和同步收集之間,選擇並發收集
    • 這是另一個簡單的規則,很容易遵循並獲得好處。並發集合比同步集合更具可擴展性,因此在編寫並行程式碼時最好使用它們。因此,下次您需要映射時,請先考慮 ConcurrentHashMap,然後再考慮 Hashtable。
  45. 如何強制啟動一個執行緒?

  46. 這是一個如何強制垃圾收集運作的問題。簡而言之,沒辦法,你當然可以使用System.gc()進行查詢,但它不能保證任何東西。在Java中絕對沒有辦法強制執行緒啟動,這是由執行緒調度程式控制的,並且Java沒有提供任何API來控制它。Java的這部分仍然是隨機的。
  47. 什麼是 Fork/Join 框架?

  48. JDK 7 中引入的 Fork/Join 框架是一個強大的實用程序,允許開發人員利用現代伺服器的多個處理器。它是為可以遞歸分解為小顆粒的工作而設計的。目標是利用所有可用的運算能力來提高應用程式的效能。該框架的一個顯著優點是它使用工作竊取演算法(從工作 - 工作和竊取 - 竊取)。已經用完作業的工作線程可以從仍然繁忙的其他線程中竊取作業。
  49. 呼叫 wait() 和 sleep() 有什麼差別?

  50. 儘管 wait 和 sleep 都代表 Java 應用程式中的一種暫停,但它們是滿足不同需求的裝置。等待用於內部線程通信,如果等待條件為真,則它會產生鎖定,如果另一個線程的操作使等待條件為假,則等待通知。另一方面,sleep() 方法只是放棄處理器或停止目前執行緒執行指定的時間。呼叫 sleep() 不會釋放目前執行緒持有的鎖定。
留言
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION