2012-06-19 105 views
3

我在我們的一個項目中遇到了一個奇怪的問題。我們使用JUnit來運行我們的單元測試,並且前一段時間,我們開始並行運行pur測試來加速執行。大多數時候,一切都很好,但有時我們幾乎所有的測試都失敗了。在下一次運行中,他們都會再次通過,而不會更改任何代碼。多線程和靜態塊

這些錯誤似乎表明某些靜態實例未正確初始化或在多線程情況下初始化完成之前使用。 (我不能調試這個,因爲這個問題從來沒有一次露面在調試的時候 - >Heisenbug

對不起,因爲它試圖重現消失的時候,我不能提供顯示的bug最小工作示例。

具體的問題是:當聲明一個像下面這樣的變量時,當另一個線程調用foo()或bar()時,a或b的初始化是否還沒有完成?我認爲靜態塊將保證在任何方法被調用之前執行。或者會有類加載器問題?或者JRE中的已知錯誤(我們目前停留在1.6.0_21,我們的IT部門尚未提供更新的版本)?

class C { 
    private static final A a; 
    private static final B b; 

    static { 
     a = new A(...); 
     b = new B(...); 
    } 

    public static void foo() { 
     useA(); 
    } 

    public static void bar() { 
     useB(); 
    } 

} 

我確定它不是硬件相關的,因爲它顯示在不同製造商的不同機器上。測試正在使用服務器虛擬機。

謝謝

阿克塞爾

+0

新A()或新B()是否開始新線程?你是否試圖找出問題並創建一個能夠再現問題的[SSCCE](http://sscce.org)? – assylias

+0

因爲我知道,使用整個類的靜態字段和方法是一個不好的做法,尤其是使用多線程。爲什麼不創建非靜態類並將其存儲在靜態字段中? – alaster

+0

這就是在這裏完成的。 a和b是提供預先計算值的類的實例。這兩個類都是不可變的,並且有方法返回這些預先計算的值。計算是在相應的類構造函數中完成的。在訪問時,只有檢查參數,計算索引並返回包含以前計算值的數組元素。 – Axel

回答

0

這是最有可能是由於併發性問題,特別是如果你打電話static東西。嘗試同步你的線程,就像這樣:

class C { 
    private static final A a; 
    private static final B b; 

    static { 
     a = new A(...); 
     b = new B(...); 
    } 

    public synchronized static void foo() { 
     useA(); 
    } 

    public synchronized static void bar() { 
     useB(); 
    } 

} 
+0

A類和B類是不可變的,且經過徹底測試的線程安全。應該沒有必要在這裏使用同步。在我們的測試中,foo()和bar()被調用了數百萬次,並且總是失敗或永遠不會失敗,所以我認爲它必須與初始化有關。 – Axel

+0

靜態字段初始化**一次**(它們與類相關而不與實例相關)。你沒有詳細說明如何從C中調用A和B實例,因此對於我來說它們在你的例子中是多餘的。 – m0skit0

+0

是的,初始化一次。而且在初始化過程中似乎出現了問題。 – Axel

0

可能有問題,如果AB創建線程或以其他方式在不同的線程中執行代碼。無論如何,你真的希望靜態是不可變的。

如果有循環依賴關係,理論上可以看到一個部分初始化的類,但這是不太可能的。