假设你有2个或更多的线程共享的对象A.我应该使用Java同步对象
对象A有它内部的一个列表,其中包含另一个对象B
对象A 名单 对象B
现在线程修改/读取对象B
问题是,什么应该是同步的? 对象A,因为他们都访问它,或对象B,因为这就是他们读取/修改
我似乎无法找到我的问题的答案在任何地方。
预先感谢
假设你有2个或更多的线程共享的对象A.我应该使用Java同步对象
对象A有它内部的一个列表,其中包含另一个对象B
对象A 名单 对象B
现在线程修改/读取对象B
问题是,什么应该是同步的? 对象A,因为他们都访问它,或对象B,因为这就是他们读取/修改
我似乎无法找到我的问题的答案在任何地方。
预先感谢
如果通过其方法之一修改对象B,则应该使该方法(或不书写的部分)同步。
要走最简单最安全的路线,您需要在对象层次结构中最外层的对象上进行同步,这应该以原子方式进行操作。
在你的例子中,你似乎需要在列表上同步(不幸的是,我不能确定没有实际的代码,你会怎么做)。
这里的示例代码:
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>();
...
此代码是_not_线程安全的,因为使用不可修饰包装的包装listOfBs确实不会使getSnapshot()线程安全的结果。 (因为add()的调用者可以修改由不可修改的包装器引用的listOfBs)。为了使这些代码是线程安全的,在包装或者使用线程安全的集合实现之前,你必须做一些类似于_copy_的列表。 – jtahlborn 2012-03-19 20:23:19
@jtahlborn谢谢,修复。 – 2012-03-19 20:26:44
在'getSnapshot()'中只有'copy.addAll(listOfBs);'需要在synchronized块中。最好限制同步的范围。 – 2012-03-19 21:15:08