2013-02-24 166 views
1

我想知道JAVA中synchronized和final之間的關係。我已經閱讀了幾篇文章,每個人都提到應該使用final字段在econstructore中初始化一個對象,否則未初始化的對象可能會在使用同一對象的多個線程之間導致同步問題。對於。例如以下代碼:JAVA中Synchronized和Final之間的關係

class FinalFieldExample { 
    final int x; 
    int y; 
    static FinalFieldExample f; 
    public FinalFieldExample() { 
    x = 3; 
    y = 4; 
    } 

    static void writer() { 
    f = new FinalFieldExample(); 
    } 

    static void reader() { 
    if (f != null) { 
    int i = f.x; 
    int j = f.y; 
    } 
} 
} 

讀者可能會正確讀取x的值,但可能會將y的值讀爲0,因爲它是nt聲明的最終值。

任何人都可以幫我解釋爲什麼會發生這種情況..?

謝謝。

+0

爲什麼你認爲「讀者可能會正確讀取x的值,但可能會讀取y的值爲0,因爲它被宣佈爲final。」? – zch 2013-02-24 00:18:38

+0

向我們展示您的所有代碼,特別是'main()'方法,它顯示您聲明的行爲,從而創建一個[SSCCE](http://sscce.org) – Bohemian 2013-02-24 00:19:14

+0

@Bohemian 2個線程,一個調用writer和一個調用讀者。 – assylias 2013-02-24 00:22:39

回答

2

這與最終字段語義有關。該JLS #17.5給出了一個很好的總結:

最終場的使用模式很簡單:設置在該對象的構造方法的對象的最終場;並且在對象的構造函數完成之前,不要在另一個線程可以看到它的地方寫入對正在構造的對象的引用。如果遵循這一點,那麼當另一個線程看到該對象時,該線程將始終看到該對象的最終字段的正確構造版本。

換句話說,假設您在構建過程中不讓this轉義,您可以保證所有線程都能看到x(即3)的正確值。

關於其他字段(y),在沒有同步的情況下,不能保證可以看到哪個值(默認值或構造函數值)。

+0

我感謝你的解釋。你能否給我提供這種類型的構造函數初始化的任何示例..? – ASingh 2013-02-24 00:29:26

+0

不知道我理解你的問題。 – assylias 2013-02-24 00:31:49

+0

你的意思是說,在上面的代碼中...我們可以得到'Y'的無效條目,因爲我有另一個線程可能調用的類對象的靜態引用....? 我沒有得到什麼'最終'在這裏做...我明白,最終使對象作爲不可變...所以如果一個線程甚至在調用構造函數之前調用靜態引用呢? 'X'和'Y'將被初始化。 所以我的問題是,我們應該如何實現一個類的構造函數,以便其他線程不能調用它,直到它被正確初始化。 – ASingh 2013-02-24 00:43:27

-1

final字段與線程無關。我懷疑你正在考慮volatile這些字段的行爲有點像你描述的那樣。

+1

最終字段在多線程環境中具有特定行爲,類似於易失性字段。 – assylias 2013-02-24 00:32:32