许多读者,一位作家:我需要同步这个吗?
我需要同步这个,当许多线程访问get方法和只有一个线程访问setList方法?许多读者,一位作家:我需要同步这个吗?
public class ListContainer {
private List<String> myList = new ArrayList<String();
public List<String> get ()
{
return new ArrayList<String>(myList);
}
public List<String> set ()
{
this.myList = computeList();
}
}
我不在乎读者是否得到旧的数据,但数据应该是一致的。
Janning
您不必进行同步(但你必须声明myList
为volatile
)如果满足以下条件:
-
computeList
不依赖于myList
当前状态
- 您在分配清单后不更改内容(
Collections.unmodifiableList(computeList())
是表达此状况的更好方法)
+1 for unmodifiableList – Poindexter 2010-02-22 16:56:26
非常感谢两位!第二个答案稍微好一点:-) – Janning 2010-02-22 17:01:00
不,您不需要同步。没有任何同时修改(如果computeList()
不取决于myList
)。
顺便说一句,为什么要退new ArrayList(myList)
,而不是简单地返回myList
?
@splix可能是因为他不希望他的列表被班级以外的客户修改。返回'myList'会暴露对列表的引用,因此客户端将能够以任何他想要的方式改变它。并且_that_将是一个经典的并发bug ... – 2010-02-22 17:05:20
你是对的,返回列表也必须是线程安全的。 – Janning 2010-02-22 17:08:29
无论computeList是否依赖myList,只要只有对myList内容的读取访问权限,就不会出现同步问题。
如果不为myList使用volatile,那么可能会发生get返回旧的myList,即使严格设置已经替换了列表。如果你不介意这种情况(这可能导致两个线程看到不同的值),那么你不需要volatile。
我宁愿做副本隐含通过
public class ListContainer {
private final List<String> myList = new CopyOnWriteArrayList<String>();
public List<String> get(){
return myList;
}
public List<String> set(){
computeList();
}
}
HTH
什么是您的computeList()呢?它取决于myList吗? – Uri 2010-02-22 16:57:38
不,不对,不好意思,不好意思 – Janning 2010-02-22 17:09:30