2013-02-25 70 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的值。当它从多个线程中调用时,一些写入可能会丢失。即使在这种情况下最初并不明显,也可能发生同样的(丢失的写入)。