首頁  >  文章  >  Java  >  關於多執行緒、垃圾收集、執行緒池和同步的常見 Java 開發人員面試問題和解答

關於多執行緒、垃圾收集、執行緒池和同步的常見 Java 開發人員面試問題和解答

DDD
DDD原創
2024-09-13 06:21:36644瀏覽

Common Java Developer Interview Questions and Answers on multithreading, garbage collection, thread pools, and synchronization

線程生命週期和管理

問題:您能解釋一下 Java 中執行緒的生命週期以及 JVM 如何管理執行緒狀態嗎?

答案:

Java 中的執行緒具有以下生命週期狀態,由 JVM 管理:

  1. New:當執行緒建立但尚未啟動時,處於new狀態。當實例化 Thread 對象,但尚未呼叫 start() 方法時,就會發生這種情況。

  2. Runnable:一旦呼叫start()方法,執行緒就進入runnable狀態。在此狀態下,執行緒已準備好運行,但正在等待 JVM 執行緒調度程序分配 CPU 時間。執行緒也可能在被搶佔後等待重新取得 CPU。

  3. 阻塞:執行緒在等待監視器鎖定釋放時進入阻塞狀態。當一個執行緒持有鎖(使用同步)並且另一個執行緒嘗試取得它時,就會發生這種情況。

  4. 等待:當執行緒無限期等待另一個執行緒執行特定操作時,執行緒會進入等待狀態。例如,執行緒可以透過呼叫 Object.wait()、Thread.join() 或 LockSupport.park() 等方法進入等待狀態。

  5. 定時等待:在此狀態下,執行緒正在等待指定的時間。由於 Thread.sleep()、Object.wait(long timeout) 或 Thread.join(long millis) 等方法,它可能處於這種狀態。

  6. 終止:執行緒在完成執行或被中止時進入終止狀態。已終止的執行緒無法重新啟動。

執行緒狀態轉換:

  • 當呼叫 start() 時,執行緒從 new 轉換為 runnable
  • 執行緒在其生命週期內可以在可運行等待定時等待阻塞狀態之間移動,具體取決於同步、等待用於鎖定或逾時。
  • 一旦執行緒的 run() 方法完成,執行緒就會進入 終止狀態。

JVM 的 執行緒調度程式 依照底層作業系統的執行緒管理功能處理 可運行 執行緒之間的切換。它決定執行緒何時以及多長時間獲得 CPU 時間,通常使用時間切片搶佔式調度


線程同步和死鎖預防

問題:Java 如何處理執行緒同步,以及可以使用哪些策略來防止多執行緒應用程式中的死鎖?

答案:

Java中的執行緒同步是使用監視器鎖定來處理的,這確保一次只有一個執行緒可以存取程式碼的關鍵部分。這通常是使用synchronized關鍵字或java.util.concurrent.locks套件中的Lock物件來實現的。詳細介紹如下:

  1. 同步方法/區塊:

    • 當執行緒進入同步方法或區塊時,它會取得物件或類別上的內在鎖定(監視器)。嘗試進入同一物件/類別上的同步區塊的其他執行緒將被阻止,直到鎖被釋放。
    • 同步區塊優於方法,因為它們允許您僅鎖定特定的關鍵部分而不是整個方法。
  2. 可重入鎖

    • Java 在 java.util.concurrent.locks 中提供了 ReentrantLock 來對鎖定進行更細粒度的控制。此鎖定提供了額外的功能,例如公平性 (FIFO) 以及嘗試逾時鎖定的能力 (tryLock())。
  3. 死鎖 當兩個或多個執行緒永遠阻塞,每個執行緒都等待另一個執行緒釋放鎖定時,就會發生死鎖。如果 A 執行緒持有鎖 X 並等待鎖 Y,而執行緒 B 持有鎖 Y 並等待鎖 X,就會發生這種情況。

防止死鎖的策略:

  • 鎖定順序:始終在所有執行緒中以一致的順序取得鎖定。這可以防止循環等待。例如,如果執行緒 A 和執行緒 B 都需要鎖定物件 X 和 Y,請確保兩個執行緒始終在 Y 之前鎖定 X。
  • 逾時:在 ReentrantLock 中使用具有逾時的 tryLock() 方法來嘗試在固定時間內取得鎖定。如果執行緒無法在時間內取得鎖,它可以後退並重試或執行其他操作,避免死鎖。
  • 死鎖偵測:工具和監控機制(例如,JVM 中的ThreadMXBean)可以偵測死鎖。您可以使用 ThreadMXBean 透過呼叫 findDeadlockedThreads() 方法來偵測是否有任何執行緒處於死鎖狀態。
   ThreadMXBean threadBean = ManagementFactory.getThreadMXBean();
   long[] deadlockedThreads = threadBean.findDeadlockedThreads();

活鎖預防:透過確保正確實現爭用處理邏輯(如後退或重試),確保執行緒不會在沒有任何進展的情況下連續更改其狀態。


垃圾收集演算法和調優

問題:您能否解釋一下 Java 中不同的垃圾收集演算法以及如何針對需要低延遲的應用程式調整 JVM 的垃圾收集器?

答案:

Java 的 JVM 提供了多種垃圾收集 (GC) 演算法,每種演算法都針對不同的用例而設計。以下是主要演算法的概述:

  1. 串列 GC:

    • 對次要和主要集合使用單一執行緒。它適用於具有單核 CPU 的小型應用程式。它對於高吞吐量或低延遲應用程式並不理想。
  2. 並行 GC(吞吐量收集器):

    • 使用多執行緒進行垃圾收集(次要GC和主要GC),從而提高吞吐量。但是,它可能會在整個 GC 週期期間在應用程式中引入長時間暫停,使其不適合即時或低延遲應用程式。
  3. G1 GC(垃圾優先垃圾收集器):

    • 基於區域的收集器,將堆劃分為小區域。它專為需要可預測暫停時間的應用程式而設計。 G1 嘗試透過限制垃圾收集所花費的時間來滿足使用者定義的暫停時間目標。
    • 適用於具有混合工作負載的大型堆(短期和長期物件)。
    • 調優:您可以使用 -XX:MaxGCPauseMillis=
  4. ZGC(Z 垃圾收集器):

    • 一個低延遲垃圾收集器,可以處理非常大的堆(數TB)。 ZGC 執行併發垃圾收集,沒有長時間的停止世界(STW)暫停。它確保暫停通常少於 10 毫秒,非常適合延遲敏感的應用程式。
    • 調整:需要最少的調整。您可以使用 -XX:+UseZGC 啟用它。 ZGC 根據堆疊大小和工作負載自動調整。
  5. 謝南多厄GC

    • 另一個低延遲GC,專注於最大限度地減少暫停時間,即使堆大小很大。與 ZGC 一樣,Shenandoah 執行並發疏散,確保暫停通常在幾毫秒範圍內。
    • 調整:您可以使用 -XX:+UseShenandoahGC 啟用它,並使用 -XX:ShenandoahGarbageHeuristics=adaptive 等選項微調行為。

針對低延遲應用程式的調整

  • 使用 併發 GC,例如 ZGCShenandoah 來最大程度地減少暫停。
  • 堆疊大小:根據應用程式的記憶體佔用調整堆大小。足夠大小的堆可以減少垃圾收集週期的頻率。使用 -Xms(初始堆大小)和 -Xmx(最大堆大小)設定堆大小。
  • 暫停時間目標:如果使用G1 GC,請使用 -XX:MaxGCPauseMillis= 設定合理的最大暫停時間目標。
  • 監控與分析:使用JVM監控工具(例如VisualVMjstat垃圾收集)來分析GC 行為。分析 GC 暫停時間完整 GC 週期頻率記憶體使用量 等指標來微調垃圾收集器。

透過根據應用程式的需求選擇正確的 GC 演算法並調整堆疊大小和暫停時間目標,您可以有效地管理垃圾收集,同時保持低延遲效能。


스레드 풀 및 실행자 프레임워크

질문: Executor 프레임워크는 Java의 스레드 관리를 어떻게 개선하며, 언제 다른 유형의 스레드 풀을 선택합니까?

정답:

Java의 Executor 프레임워크는 스레드 관리를 위한 더 높은 수준의 추상화를 제공하므로 스레드 생성 및 수명 주기를 직접 관리하지 않고도 작업을 비동기적으로 더 쉽게 실행할 수 있습니다. 프레임워크는 java.util.concurrent 패키지의 일부이며 ExecutorServiceExecutors.

와 같은 클래스를 포함합니다.
  1. Executor Framework의 이점:

    • 스레드 재사용성: 프레임워크는 각 작업에 대해 새 스레드를 생성하는 대신 여러 작업에 재사용되는 스레드 풀을 사용합니다. 이렇게 하면 스레드 생성 및 삭제에 따른 오버헤드가 줄어듭니다.
    • 작업 제출: Runnable, Callable 또는 Future를 사용하여 작업을 제출할 수 있으며 프레임워크는 작업 실행 및 결과 검색을 관리합니다.
    • 스레드 관리: 실행자는 유휴 기간 동안 스레드 시작, 중지, 활성 상태 유지 등의 스레드 관리를 처리하여 애플리케이션 코드를 단순화합니다.
  2. **종류

스레드 풀**:

  • 고정 스레드 풀(Executors.newFixedThreadPool(n)):

    고정된 개수의 스레드로 스레드 풀을 생성합니다. 모든 스레드가 사용 중이면 스레드를 사용할 수 있을 때까지 작업이 대기열에 추가됩니다. 이는 작업 수를 알고 있거나 동시 스레드 수를 알려진 값으로 제한하려는 경우 유용합니다.

  • 캐시된 스레드 풀(Executors.newCachedThreadPool()):

    필요에 따라 새 스레드를 생성하지만 이전에 생성된 스레드가 사용 가능해지면 재사용하는 스레드 풀을 생성합니다. 단기 작업이 많은 애플리케이션에 이상적이지만 작업이 장기 실행되는 경우 무제한 스레드 생성이 발생할 수 있습니다.

  • 단일 스레드 실행자(Executors.newSingleThreadExecutor()):

    단일 스레드는 작업을 순차적으로 실행합니다. 이는 작업을 순서대로 실행해야 할 때 유용하며 한 번에 하나의 작업만 실행되도록 합니다.

  • 예약된 스레드 풀(Executors.newScheduledThreadPool(n)):

    지연 후 또는 주기적으로 실행되도록 작업을 예약하는 데 사용됩니다. 고정된 간격으로 작업을 예약하거나 반복해야 하는 애플리케이션(예: 백그라운드 정리 작업)에 유용합니다.

  1. 올바른 스레드 풀 선택:
    • 동시 작업 수가 제한되어 있거나 미리 알려진 경우 고정 스레드 풀을 사용하세요. 이렇게 하면 너무 많은 스레드로 인해 시스템이 과부하되는 것을 방지할 수 있습니다.
    • 예측할 수 없거나 작업량이 급증하는 애플리케이션에는 캐시된 스레드 풀을 사용하세요. 캐시된 풀은 단기 작업을 효율적으로 처리하지만 제대로 관리하지 않으면 무한정 커질 수 있습니다.
    • 직렬 작업 실행에는 단일 스레드 실행기를 사용하여 한 번에 하나의 작업만 실행되도록 합니다.
    • 백그라운드 데이터 동기화나 상태 확인과 같은 주기적인 작업이나 지연된 작업 실행에는 예약된 스레드 풀을 사용하세요.

종료 및 자원 관리:

  • 더 이상 필요하지 않은 리소스를 해제하려면 항상 shutdown() 또는 shutdownNow()를 사용하여 실행 프로그램을 적절하게 종료하세요.
  • shutdown()을 사용하면 현재 실행 중인 작업을 완료할 수 있고, shutdownNow()는 실행 중인 작업을 취소하려고 시도합니다.

Executor 프레임워크를 사용하고 애플리케이션의 워크로드에 적합한 스레드 풀을 선택하면 동시성을 보다 효율적으로 관리하고 작업 처리를 개선하며 수동 스레드 관리의 복잡성을 줄일 수 있습니다.

以上是關於多執行緒、垃圾收集、執行緒池和同步的常見 Java 開發人員面試問題和解答的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn