2010-09-01 22 views
6

可能重複:
Thread safety in Java classJava併發 - 爲什麼不同步setter(但不是getter)使類是線程安全的?

我讀的實踐Java併發,我已經得出這樣的困惑我舉一個例子。

作者認爲這個類是不是線程安全的

public class MutableInteger { 

    private int number; 

    public int getInt() { 
     return number; 
    } 

    public void setInt(int val) { 
     number = val; 
    } 
} 

而且他們還指出,同步只有一個方法(二傳手例如)不會做;你必須同步兩者。

我的問題是:爲什麼?不會讓二傳手同步嗎?

+0

其實它是微妙的不同。 – 2010-09-01 07:56:30

回答

5

Java在內存模型之前發生/發生。在寫入路徑和讀取路徑上都需要有一些通用的併發構造(例如同步塊/方法,鎖定,易失性,原子)來觸發這種行爲。

如果同步這兩個方法,您將在將由讀取和寫入線程共享的整個對象上創建一個鎖。 JVM將確保寫入線程在離開(同步)setInt方法之前發生的任何更改在進入(同步)getInt方法後對任何讀取線程均可見。 JVM將插入必要的內存屏障以確保這會發生。

如果只有寫入方法已同步,則對該對象的更改可能對任何閱讀線程都不可見。這是因爲JVM可以用來確保讀線程的可見內存(緩存等)與寫線程一致的讀路徑上沒有任何意義。使getInt方法同步將提供。

注意:特別是在這種情況下,將字段'數字'設置爲volatile將會給出正確的行爲,因爲易失性讀/寫也會在JVM中提供相同的內存可見性行爲,並且setInt方法內部的操作只是一項分配。

+0

這是一條典型的註釋行。 – 2010-09-01 07:41:46

+0

使字段'數字'變爲volatile並不會使賦值操作成爲原子。該方法必須同步 – John 2011-02-22 18:22:28

+0

解釋實際的故障情況,如果該字段是易失性的並且該方法未同步。 – 2011-02-23 00:41:03

-1

因爲number不是易失性的,並且getInt()不同步,getInt()可能會返回陳舊值。有關更多信息,請閱讀有關Java內存模型的內容。

+0

對不起,答案至少不完整,對我的眼睛毫無用處。他問一個具體問題的解釋(-1) – 2010-09-01 07:39:51

5

它在本書的例子之前解釋(第35頁):

「同步只是二傳手是不夠的:線程調用get仍然能夠看到過時的值。」

陳舊數據:當閱讀器線程檢查就緒時,它可能會看到過時的值。每次訪問變量時,除非使用同步,否則可能會看到該變量的陳舊值。更糟糕的是,陳舊程度並非全是或無:一個線程可以看到一個變量的最新值,而是先寫入的另一個變量的陳舊值。

+0

**我**閱讀這本書,說「它將能夠看到陳舊的價值」是不夠的,我想要的基礎。 – 2010-09-01 19:17:24

+0

所以,你不相信,如果吸氣劑不同步,你想要一個證明它,或者你是什麼意思,有沒有可能看到陳舊的價值? – Soundlink 2010-09-01 22:56:49

+0

我想明白爲什麼。原因是線程保留變量的本地緩存值,讀取可能不會刷新緩存。如果緩存不在那裏,那麼是否有同步方法並不重要(兩個操作都是原子操作) – 2010-09-02 15:25:18

1

如果您只是同步setter方法,則只能保證該屬性不會被錯誤地修改,但當您嘗試讀取該變量時無法確定它是陳舊值。

相關問題