2012-03-19 81 views
2

假设你有2个或更多的线程共享的对象A.我应该使用Java同步对象

对象A有它内部的一个列表,其中包含另一个对象B

对象A 名单 对象B

现在线程修改/读取对象B

问题是,什么应该是同步的? 对象A,因为他们都访问它,或对象B,因为这就是他们读取/修改

我似乎无法找到我的问题的答案在任何地方。

预先感谢

回答

0

如果通过其方法之一修改对象B,则应该使该方法(或不书写的部分)同步。

2

要走最简单最安全的路线,您需要在对象层次结构中最外层的对象上进行同步,这应该以原子方式进行操作。

在你的例子中,你似乎需要在列表上同步(不幸的是,我不能确定没有实际的代码,你会怎么做)。

这里的示例代码:

class B { 
} 

class A { 
    private final List<B> listOfBs = new ArrayList<B>(); 

    void add(B b) { 
     synchronized (listOfBs) { 
      listOfBs.add(b); 
     } 
    } 

    List<B> getSnapshot() { 
     List<B> copy = new ArrayList<B>(); 
     synchronized (listOfBs) { 
      copy.addAll(listOfBs); 
     } 
     return copy; 
    } 
} 

请注意,您需要申报清单,final消除的可能性,有些代码可能会改变参考违反原子列表:

// will make add() and getSnapshot() not mutually exclusive, thus violating atomicity of operations 
    ... 
    listOfBs = new ArrayList<B>(); 
    ... 

阅读Java concurrent programming tutorial将有所帮助。

+0

此代码是_not_线程安全的,因为使用不可修饰包装的包装listOfBs确实不会使getSnapshot()线程安全的结果。 (因为add()的调用者可以修改由不可修改的包装器引用的listOfBs)。为了使这些代码是线程安全的,在包装或者使用线程安全的集合实现之前,你必须做一些类似于_copy_的列表。 – jtahlborn 2012-03-19 20:23:19

+0

@jtahlborn谢谢,修复。 – 2012-03-19 20:26:44

+0

在'getSnapshot()'中只有'copy.addAll(listOfBs);'需要在synchronized块中。最好限制同步的范围。 – 2012-03-19 21:15:08