2013-04-12 35 views
1

Java規範17.5具有下面的代碼來說明使用最終字段在Java存儲模型的。 (相比於普通字段)這不是用Java解釋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; // guaranteed to see 3 
      int j = f.y; // could see 0 
     } 
    } 
} 

該規範接着說:

「類FinalFieldExample有一個最終詮釋現場x和非最終詮釋字段,Y的 一個線程可以執行。由於writer方法在對象的構造器完成後寫入f,讀者方法將保證看到fx的正確初始化值:它將讀取值3. 但是,fy是不是最終的;讀者的方法因此不能保證看到它的價值4。「

我的問題是:這不是一個跛腳(或至少是一個非常做作)的例子嗎? 還是我失去了一些東西?

我的推理項的實例爲「跛」是:

如果FinalFieldExample類的對象要被通過螺紋在一個多線程的情況下共享,不應該它遵循多線程的基本原則,這是使用某種形式的同步。如果他們使用過同步,那麼提到的問題將不存在。

上述例子似乎主張最終字段作爲適當的同步技術的替代(或部分橡皮奶頭)。根據我的理解,即使在正確的同步之上使用最終字段也是有用的。並且不應該被用來獲得示例中提到的優勢(在沒有同步的情況下)。

所以人們可能要問: 是不是有一個體面的例子(同步於)解釋過正常的域最終場的優勢在哪裏?我猜,不可變性是!

+1

它就是當前內存模型下最終字段發生情況的一個例子。這不是主張你寫這樣的代碼。請參閱JCIP以獲取有關如何編寫併發代碼的建議,其中基本原則是「儘可能使用更高級別的構造(在java.util.concurrent中)」。 –

+0

@NathanHughes:您的評論非常有趣。你能否在JCIP中提供一個參考文件(在使用更高層次的結構時)?謝謝 ! – brainOverflow

+0

嘗試JCIP的這句話,第5章開始:「在實際情況下,委派是創建線程安全類最有效的策略之一:讓現有線程安全類管理所有狀態。」 –

回答

4

你混淆了synchronization和併發性。

如果一個字段是一個常量,那麼它可以安全地在多個Thread之間共享,而不需要任何鎖定。

如果一個字段是一個變量,那麼它需要是​​或以其他方式鎖定。

你可以有一個併發程序有多個線程讀取相同的常量字段,這不會阻止任何Thread s。

任何使用​​塊的代碼都會產生這樣的巨大的成本。這是一個非常昂貴的過程,應儘可能避免。更不用說資源匱乏,死鎖,活鎖等問題了......

如果您可以使用final而不是​​您應該這樣做。

+0

「如果一個字段是一個變量,那麼它需要被同步或鎖定。」確實!這也是我的觀點。由於在這個例子中有一個變量(即非最終),它必須已經同步。這個例子似乎是故意構建的,允許非法訪問非最終字段,然後聲稱這是最終字段的用例。 – brainOverflow

+2

@vendhan不!這是JVM如何運行的一個例子。 JLS不是用例列表,它是對語言規範的描述。這是「final」和「non-final」字段的行爲如何不同的例子。 –

+0

這是JLS的一個合理的論點!謝謝 ! – brainOverflow

3

編輯:我錯過了這個答案的地步。問題不在於價值可以改變。請參閱bmorris591的回答。

不可變對象的一個​​優點是您不需要同步。

但是這個例子不是關於同步,而是讀者線程保證看到的值。即使有同步的y價值可能發生變化,而x值總是保證是3

+0

哇!你能否告訴我們,即使正確的同步,y的價值可能被誤讀? – brainOverflow

+0

@vendhan正確同步不,它不能。沒有它當然可以。關鍵是,雖然y是一個常數,但仍然可能被誤讀,因爲它不是「最終」。 –

+2

這不是它可能被誤讀,而只是它可以被另一個線程改變。 – WilQu

1

你引用的這個規範只是描述了東西(應該)的行爲。根據此規範,您可以決定如何正確編碼。這個例子絕不會試圖代表一個真實的用例。它只是用幾行說明行爲是什麼。如果你的jvm實現不像那樣,那麼它就是一個bug。

相關問題