2017-05-21 119 views
2

在多線程環境中,類的靜態塊保證在其他靜態方法(在同一個類中)被調用之前完成?靜態方法和靜態塊之間的線程安全

我不是說在靜態塊本身調用其他靜態方法的情況下。爲了澄清,我們可以使用下面的代碼塊。

外部類可以啓動兩個線程,兩個線程都會調用OurClass.doSomething(),並且一個線程會在靜態塊結束之前開始執行?

public class OurClass { 

    static { 
    // does something that takes a long time 
    } 

    public static void doSomething() { 
    // can I be called before the block has finished? 
    } 
} 
+2

如果靜態塊本身調用任何靜態方法會怎麼樣? – Eran

+0

這取決於。請給出一個特定的代碼作爲例子。 – davidxxx

回答

3

可以在外線類啓動兩個線程,這兩個調用 OurClass.doSomething(),和一個他們將開始 靜態塊完成之前執行?

不,這在Java的兼容實現中是不可能的。

參見section 12.4.1 of the Java Language Specification

類或接口類型T 將緊接在以下中的任何一個的 第一次出現之前被初始化

  • T是一個類和T的實例被創建。

  • 調用由T聲明的靜態方法。

  • 指定由T聲明的靜態字段。

  • 使用由T聲明的靜態字段,該字段不是常量變量(§4.12.4)。

  • T是頂級類(第7.6節),並且在T(§8.1.3)中執行詞法嵌套的斷言語句(第14.10節)。

而且section 12.4 just above this text介紹這是什麼意思「初始化類T型」:

一類的初始化包括執行其靜態 初始化和靜態字段的初始化(類變量) 在類中聲明。


有關類初始化的多線程/存儲器型號含義詳情一個需要讀取部分12.4.2(」 12.4.2. Detailed Initialization Procedure")。

總之,本節說明的是,無論何時Java想要使用特定的類C,它都需要採取行動,就好像它獲得了該類C *上的同步鎖LC

然後它需要檢查類是否已經被初始化。只有在課程完全初始化後,纔可以對該課程採取任何行動。如果它尚未初始化,並且沒有被另一個線程初始化,則此時需要初始化該類。

具體到您的評論,部分12.4.2規定,一旦對這一類同步鎖:

如果對C類對象指示初始化正在進行 對於C當前線程,那麼這必須是一個 初始化的遞歸請求。釋放LC並正常完成。

+0

(首先,感謝您在規範中正確位置的鏈接)。 但是,這個描述似乎與@Eran上面寫過的情況相矛盾,在這種情況下,靜態塊調用一個靜態方法(在靜態塊結束之前的確會被執行)。 – Eyal

+1

這很接近,它看起來像血淋淋的細節這是在12.4.2 –

+0

@NathanHughes是的,我只是試圖總結12.4.2的細節 –