2010-02-22 63 views
4

我需要同步这个,当许多线程访问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

+1

什么是您的computeList()呢?它取决于myList吗? – Uri 2010-02-22 16:57:38

+0

不,不对,不好意思,不好意思 – Janning 2010-02-22 17:09:30

回答

5

您不必进行同步(但你必须声明myListvolatile)如果满足以下条件:

  • computeList不依赖于myList
  • 当前状态
  • 您在分配清单后不更改内容(Collections.unmodifiableList(computeList())是表达此状况的更好方法)
+2

+1 for unmodifiableList – Poindexter 2010-02-22 16:56:26

+0

非常感谢两位!第二个答案稍微好一点:-) – Janning 2010-02-22 17:01:00

1

不,您不需要同步。没有任何同时修改(如果computeList()不取决于myList)。

顺便说一句,为什么要退new ArrayList(myList),而不是简单地返回myList

+2

@splix可能是因为他不希望他的列表被班级以外的客户修改。返回'myList'会暴露对列表的引用,因此客户端将能够以任何他想要的方式改变它。并且_that_将是一个经典的并发bug ... – 2010-02-22 17:05:20

+0

你是对的,返回列表也必须是线程安全的。 – Janning 2010-02-22 17:08:29

0

无论computeList是否依赖myList,只要只有对myList内容的读取访问权限,就不会出现同步问题。

如果不为myList使用volatile,那么可能会发生get返回旧的myList,即使严格设置已经替换了列表。如果你不介意这种情况(这可能导致两个线程看到不同的值),那么你不需要volatile。

0

我宁愿做副本隐含通过

public class ListContainer { 

    private final List<String> myList = new CopyOnWriteArrayList<String>(); 

    public List<String> get(){ 
     return myList; 
    } 

    public List<String> set(){ 
     computeList(); 
    } 
} 

HTH