2012-11-27 33 views
3
public class Stuff { 
    private final Timer timer = new Timer(true); 
    public static final int DEFAULT_TIMEOUT = 1500; 
    private volatile int timeout = DEFAULT_TIMEOUT; 


    public void doStuff(OtherStuff) { 
    ... 
    timer.schedule(timeout, ...); 
    } 

    public void setTimeout(int timeout) { 
    this.timeout = timeout; 
    } 

    public int getTimeout() { 
    return timeout; 
    } 

} 

該類的實例只能從1個線程訪問,但可以從另一個類中更改的超時變量除外。在我的情況下,一個JMX bean,這意味着可以通過管理界面在運行時改變超時。 ()可以運行100次/秒,而setTimeout()可以每週運行一次 - 所以在執行setTimeout()和執行doWork()的人之間的排序並不重要。Java,會不會揮發也保證可視性?

是否使timeout對這種情況足夠揮發?內存模型是否可以保證從一個線程對doStuff()方法可見?

,似乎安全的另一種方法,簡直是:

public class Stuff { 
    private final Timer timer = new Timer(true); 
    public static final int DEFAULT_TIMEOUT = 1500; 
    private int timeout = DEFAULT_TIMEOUT; 
    public void doStuff(OtherStuff) { 
    ... 
    timer.schedule(getTimeout(), ...); 
    } 

    public void synchronized setTimeout(int timeout) { 
    this.timeout = timeout; 
    } 
    public int synchronized getTimeout() { 
    return timeout; 
    } 
} 

以下哪種方法2將是首選?

回答

7

從能見度的角度來看,兩種方法都是等價的。任何對隨後在同一個易失性變量上寫入的易失性數據的讀取都會保證能夠看到寫入數據。

因此,如果一個線程寫入timeout = newValue;,隨後調用timer.schedule(timeout)的任何其他線程保證看到newValue

這保證在JLS 17.4.5指定:

於揮發性字段(§8.3.1.4)之前發生該字段的每個後續的讀寫。

我會簡單地使用volatile作爲它提供的保證是足夠的,它清楚地表明你的意圖。

+0

實際上沒有保證:) –

+0

@MarkoTopolnik我希望你不會遇到這個!現在我們有一個困惑的OP! – assylias

+0

我忍不住自己:)但基本上,使用「強有力的承諾」而不是「保證」是正確和有益的。閱讀「隨後」與定期掛鐘時間的含義可能會更令人困惑,因爲有些東西無法以這種方式理解。 –