2012-03-08 29 views
2

这种流利的类并不严格不变,因为这些字段不是最终的,但是它是线程安全的,为什么?像使用clone()和非final字段的类一样流畅的线程安全

我关心的线程安全问题不是竞争条件,而是变量的可见性。我知道有一个使用最终变量和构造函数而不是clone()+赋值的解决方法。我只想知道这个例子是否可行。

public class IsItSafe implements Cloneable { 

    private int foo; 
    private int bar; 

    public IsItSafe foo(int foo) { 
     IsItSafe clone = clone(); 
     clone.foo = foo; 
     return clone; 
    } 

    public IsItSafe bar(int bar) { 
     IsItSafe clone = clone(); 
     clone.bar = bar; 
     return clone; 
    } 

    public int getFoo() { 
     return foo; 
    } 

    public int getBar() { 
     return bar; 
    } 

    protected IsItSafe clone() { 
     try { 
      return (IsItSafe) super.clone(); 
     } catch (CloneNotSupportedException e) { 
      throw new Error(e); 
     } 
    } 
} 
+0

通过制作IsItSafe final,您可以使这个更安全一些。你是否担心有人用反射改变foo或bar?你为什么关心他们的知名度? – alpian 2012-03-08 17:59:15

+0

我并不担心有人通过反思或扩展课程来改变这个领域。我在问,因为我设计了一个类似的课程,其线程安全性受到了质疑。 – 2012-03-08 18:09:31

+0

仅供参考,我在这里发布了这个问题的延续:http://stackoverflow.com/questions/9633771/how-can-one-break-this-non-thread-safe-object – assylias 2012-03-09 12:04:32

回答

1

您在设置字段时没有持有锁定,并且当您提到自己字段不是最终字段时。

因此,从可见性的角度来看,这种方法不是线程安全的。

进一步澄清这里:https://stackoverflow.com/a/9633968/136247

关于使用挥发性的问题更新:

对于这里使用挥发性修复线程问题争论的缘故。
但是你应该重新考虑最终场和一个拷贝构造函数,因为:

  • 现场访问将略快(在读总是可以来自CPU高速缓存)
  • 您避免不鼓励使用的clone(见效果Java的由乔希布洛赫)
  • 构造与最终的领域是一成不变的类已知的成语,将由代码
  • 打标领域volatile而打算对他们是不可改变的读者很容易识别是在我和一对矛盾tself;)
+0

是的,但从逻辑的角度来看,它是 – 2012-03-09 12:11:17

+0

我不确定您的意思是* logical *。你的意思是*实用*吗?或者你的意思是如果没有Java内存模型,这是伪代码? – Joe23 2012-03-09 12:23:58

+0

因此,将这些字段标记为volatile会解决可见性问题,对吗? – 2012-03-09 13:49:05

1

这个thread是相当一致的,因为可见性问题该类不是线程安全的。

你为什么说这个类不是不可变的?该类的状态由foo和bar定义,对于任何特定的实例,一旦创建实例,该类就不能从类外部更改。所以它是不可变的,即使这些字段没有明确声明为最终的。

foo和bar被改变的唯一地方(在foo()和bar()方法中),更改是在局部变量上完成的,该变量一次只能由一个线程访问。

编辑

我觉得这是在Java并发规定在实践中(3.3.2),这使得把foo()和bar()方法的线程安全的,因为clone不是堆栈约束的例子允许在完全构建之前逃避该方法。

局部变量本质上局限于正在执行的三元组;它们存在于执行线程的堆栈上,而其他线程无法访问它。

+0

这就是我的想法,但我有一个疑问。如果foo()或bar()返回的实例与另一个线程共享,它会看到bar或foo的更新值吗? – 2012-03-08 16:48:18

+3

Downvoter?谨慎解释? – assylias 2012-03-08 16:55:59

+1

(我不是downvoter。)关于你不可改变的论点:你认为指令重新排序?如果你在这里说的是对的,那么就不需要最终的修饰符来创建线程安全的不可变对象。关于你的堆栈限制参数:堆栈局部变量是'clone'。可见性问题涉及'foo'和'bar'字段,这显然不是堆栈本地的。 – Joe23 2012-03-08 19:08:08

相关问题