1. 程式人生 > 其它 >static塊初始化

static塊初始化

參考

靜態塊的執行時機

每當發生以下事件之一時,ClassLoader 都需要載入 Class:

  • 靜態成員變數由應用程式設定(應用程式是指包含靜態塊的類之外的程式碼)
  • 應用程式訪問非最終靜態成員變數
  • 應用程式呼叫靜態方法
  • Class.forName("...")
  • 使用 Class.newInstance() 或通過 new 關鍵字建立例項

由於靜態塊的使用是在類的初始化/載入中(應該只發生一次),因此該塊被 JVM 視為“同步”塊。只有當類狀態為“未初始化”時,執行緒才能訪問此程式碼塊。由於有多個上述事件可以觸發類載入,JVM 需要確保類載入/初始化只發生一次。為了確保這一點,每個類都有一個“初始化鎖”,它由首先到達靜態塊的執行緒獲取,並且只有在靜態塊程式碼執行完成後才會釋放鎖。

在此之前,其他執行緒在任何活動上都會被阻塞,例如嘗試載入類或建立例項。一旦鎖被釋放,類的狀態被設定為“完全初始化”,不需要任何其他執行緒進入靜態塊。

初始化鎖舉例

Test.java

public class Test {
    static {
        System.out.println("Entered static block by thread " + Thread.currentThread().getName());
        try {
            Thread.sleep(10000);
            System.out.println("Finished static block by thread " + Thread.currentThread().getName());
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

Main.java

public class Main {
    public static void main(String[] args) {
        ExecutorService executorService = Executors.newFixedThreadPool(2);
        executorService.submit(() -> Class.forName("org.priya.Test"));
        executorService.submit(() -> {
            final Test test = new Test();
            System.out.println("Object created by thread " + Thread.currentThread().getName());
        });
    }
}

初始化鎖導致的死鎖

當一個類中的靜態塊程式碼觸發另一個類的類載入事件,那個類中也有一個靜態塊,靜態塊又依賴於當前類,就會引入死鎖,導致java.lang.ClassNotFoundException異常。

死鎖程式碼