2010-02-22 51 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