25

我在 dos.oracle.com 找到了这个

公共静态列表同步列表(列表列表)

返回由指定列表支持的同步(线程安全)列表。为了保证串行访问,对后备列表的所有访问都通过返回的列表完成是至关重要的。用户在迭代返回的列表时必须手动同步它:

  List list = Collections.synchronizedList(new ArrayList());
      ...
  synchronized(list) {
      Iterator i = list.iterator(); // Must be in synchronized block
      while (i.hasNext())
          foo(i.next());
  }

Collections.synchronizedList();我的问题是:如果应该返回一个已经同步的列表,为什么我必须同步列表来迭代它?

我只是在两个线程中访问列表:一个线程只是添加,另一个线程来获取和删除。您建议在这种情况下使用哪些其他类?

谢谢阅读。

4

2 回答 2

30

正在同步的列表仅意味着addremove操作是同步的,因此是原子的。然而,迭代不是,如果一个线程adds在另一个线程进行迭代时,您可能会得到一个 ConcurrentModificationException。

通过手动同步您的迭代块,您可以确保列表在迭代时不会被修改。

一种替代方法是使用aCopyOnWriteArrayList,它提供了一个迭代器,该迭代器在迭代开始时对列表进行迭代,而不管后续修改如何。但是,如果您需要经常更改列表的内容,则该集合不是很有效。

于 2013-08-01T12:45:41.047 回答
-1

一开始我对这个话题有点困惑,因为我发现的大多数例子都没有上下文。我终于找到了这篇博客文章,为我解决了问题:http: //netjs.blogspot.de/2015/09/how-and-why-to-synchronize-arraylist-in-java.html

从上面的示例看来,我只需要使用 Collections.synchronizeList() 转换我的列表,然后我就可以添加和删除项目而不必担心线程安全。但是在这里需要注意的是,在将列表传递给不同的线程之前,您必须同步列表,因为否则列表访问不是互斥的。

所以一个完整的例子是:

public class SynchroProblem implements Runnable{
  private List<Integer> myList;

  //Constructor
  public SynchroProblem(List<Integer> myList){
    this.myList = myList;
  }

  @Override
  public void run() {
    // Do stuff with the list .add(), .remove(), ...
    myList.add(5);

    // Even if mylist is synchronized the iterator is not, 
    // so for using the iterator we need the synchronized block
    synchronized (myList){
      // do stuff with iterator e.g.
      Iterator<Integer> iterator = myList.iterator();
      while (iterator.hasNext()){
        int number = iterator.next();
        if (number == 123){
          iterator.remove();
        }
      }

    }
  }

  public static void main(String[] args) {

    List<Integer> originalList = new ArrayList<Integer>();

    // Synchronize list
    List<Integer> syncList = Collections.synchronizedList(originalList);

    // Create threads and pass the synchronized list
    Thread t1 = new Thread(new SynchroProblem(syncList));
    Thread t2 = new Thread(new SynchroProblem(syncList));

    t1.start();
    t2.start();

  }
}
于 2016-09-23T13:34:45.453 回答