2013-02-25 66 views
7

比方說,我有以下的,是String get/set線程安全嗎?

public class Foo{ 
    private String bar; 

    public String getBar(){ 
     return bar; 
    } 

    public void setBar(String bar){ 
     this.bar = bar; 
    } 
} 

由於String類的不可變的性質是這些方法會自動線程安全的,或者需要某種鎖定機制?

+2

我假設你是指'setter中的'String'。 – 2013-02-25 17:18:54

+0

@TheodorosChatzigiannakis,是的,我的錯!固定。 – mre 2013-02-25 17:19:10

+1

相關的c#問題:http://stackoverflow.com/questions/3595114/why-are-immutable-objects-thread-safe – PermGenError 2013-02-25 17:20:03

回答

18

不,這不是線程安全的。 Foo是可變的,所以如果你想確保不同的線程看到的bar相同的值 - 即,一致性 - 無論是:

  • barvolatile,或
  • 製作方法​​,或
  • 使用AtomicReference<String>

bar的讀取和寫入本身是原子的,但原子性不是線程安全的。

http://docs.oracle.com/javase/tutorial/essential/concurrency/atomic.html


爲深入Java併發的覆蓋面,搶Java Concurrency in Practice (aka JCIP)副本。

+4

+1或簡單地聲明'bar'爲'final',所以引用不能被重新賦值給另一個值。當然,那裏不會有任何制定者:) – 2013-02-25 17:25:25

+1

這是不可改變的。在這種情況下不需要二傳手。而且你必須確保提供一個構造函數來初始化該值,因爲在這種情況下,一旦你退出構造函數就無法更改它。 – duffymo 2013-02-25 17:41:42

+0

...出於好奇,做這兩件事實際上很重要嗎?我的意思是,如果你的實際問題是一種競爭條件,儘管有'易失性'或'同步',它仍然會發生 - 它只是減少它可能發生的'窗口',對吧?或者我在這裏錯過了什麼? – 2013-02-25 18:09:57

4

不,不安全。

這是Foo可變行爲; String的不可變性不會累積到Foo。

public class Foo{ 
    private String bar; 

    public synchronized String getBar(){ 
     return bar; 
    } 

    public synchronized void setBar(String bar){ 
     this.bar = bar; 
    } 
} 
+0

+1同步getBar()'怎麼辦?也許某個線程爲'bar'設置一個新值,而其他線程讀取'bar'。 – 2013-02-25 17:30:26

+0

對不起,你對我沒有意義。我認爲你的意見只是混淆了這個問題。 – duffymo 2013-02-25 17:46:33

+0

@duffymo做了一個非同步的getter和線程間同步setter保證一致性? – 2013-02-25 17:50:26

7

您正在設置參考,因此String的不變性不起作用。您不會影響String的內容。

3

不,它不是線程安全的。

雖然String是不可變的,但問題來自Foo的字段。爲了使這一點更加明顯,例如考慮一種方法,其作業將是附加(而不是替換)bar的值。當它從多個線程中調用時,一些寫入可能會丟失。即使在這種情況下最初並不明顯,也可能發生同樣的(丟失的寫入)。