2010-08-30 55 views
15

爲什麼此java類不是線程安全的。Java類中的線程安全性

class TestClass { 
    private int x; 

    int get() { 
     return x; 
    } 

    void set(int x) { 
     this.x = x; 
    } 
} 

我看了那個關鍵字​​是否需要讓它線程安全?畢竟不是在原子內完成的操作?

+1

private void int x? – 2010-08-30 16:58:50

回答

11

雖然賦值本身是一個原子操作,但由於不同的硬件和編譯器實現,不同的線程可能會看到成員x的不同值。即,由於某種緩存,一個線程的修改可能對另一個線程不可見。這通常被稱爲線程可見性問題

通過在監視器上同步(使用synchronized關鍵字或java.util.concurrent鎖)或通過聲明x是易失性的,您可以正確地同步代碼。

+0

在C#中也是這樣嗎? – devnull 2010-08-30 17:11:04

8

對於多個處理器,某些值可能會被處理器緩存,並且可能不會反映其他線程/處理器對同一對象所做的更改。實際上,即使使用單個處理器,JVM也可以實現這種工作方式。

語言規範明確要求同步方法呈現內存屏障並要求從內存中重讀所有實例變量。

因爲您的代碼不同步,所以一個線程可能會設置該值,但另一個線程將返回仍由該線程緩存的值。

請閱讀'Memory and Locks'章節的Java語言規範。

+1

downvote的原因是什麼? – 2010-08-30 17:07:25

5

因爲字段'x'沒有被聲明爲volatile,所以沒有要求JVM確保'x'對所有其他線程都可見。即如果一個線程不斷讀取'x'的值並且另一個線程正在寫入它,那麼讀線程可能永遠不會「看見」值更改。

不需要同步關鍵字,但會起作用,因爲它將創建必要的內存屏障/緩存刷新以確保「x」可見,但在這種情況下使用volatile關鍵字會更有效。

1

當您有兩種方法修改/訪問非易失性變量時,它永遠不會線程安全。如果你想只有一種方法,你可以嘗試:

synchronized int getAndSet(int x, boolean set) { 
    if (set) this.x = x; 
    return this.x; // param x is for set 
}