如何创建Synchronized arraylist

Lal*_*and 12 java multithreading synchronization

我已经像这样创建了synchronized arrayList

import java.text.SimpleDateFormat;
import java.util.*;


class HelloThread  
{

 int i=1;
 List arrayList;
  public  void go()
  {
 arrayList=Collections.synchronizedList(new ArrayList());
 Thread thread1=new Thread(new Runnable() {

  public void run() {
  while(i<=10)
  {
   arrayList.add(i);
   i++;
  }
  }
 });
 thread1.start();
 Thread thred2=new Thread(new Runnable() {
  public void run() {
     while(true)
     {
   Iterator it=arrayList.iterator();
      while(it.hasNext())
      {
       System.out.println(it.next());
      }
     }
  }
 });
 thred2.start();
  }
 }

public class test
{
  public static void main(String[] args)
  {
   HelloThread hello=new HelloThread();
   hello.go();
  }
}
Run Code Online (Sandbox Code Playgroud)

但是像这样得到例外

线程"Thread-1"中的异常java.util.ConcurrentModificationException

我的方法有什么不对吗?

axt*_*avt 27

IteratorsynchronizedList是没有(不能)同步,您需要在列表中手动同步,而迭代(见的javadoc):

synchronized(arrayList) {
    Iterator it=arrayList.iterator(); 
    while(it.hasNext()) { 
        System.out.println(it.next()); 
   } 
}
Run Code Online (Sandbox Code Playgroud)

另一种方法是使用a CopyOnWriteArrayList代替Collections.synchronizedList().它实现了写时复制语义,因此不需要同步.


Ste*_*n C 12

其他答案已经确定了问题:

  • 同步集合的迭代器不同步.实际上,它们只是包装类中的集合对象返回的迭代器.

  • 许多集合类(包括ArrayList)使用故障快速机制来检测迭代期间的并发修改.在各个类的javadoc中清楚地记录了这种行为.这就是你所看到的.

并非所有集合类都这样做.例如,许多java.util.Concurrent...集合类允许在迭代期间进行并发修改,但放宽迭代序列的语义,以便修改的结果在迭代器返回的对象中可能显而易见,也可能不显示.

用于Collections.synchronizedList() 解释如何同步迭代器的javadoc .基本上你这样做:

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

(旁白:通常认为做这样的事情会起作用是不安全的.理论上,同步列表可以使用私有锁对象,并且该synchronized语句不会锁定并发修改.但是javadocs说这是什么做这种情况......所以这是安全的.)

这样做的问题是锁定集合会产生潜在的并发瓶颈.替代方法是使用写时复制数据结构,该数据结构在内部复制集合的相关部分.这种方法意味着迭代器看到了集合的快照.可以与迭代同时对集合进行修改,但迭代器不会看到它们.写时复制的问题在于修改可能要贵得多.

最终,您需要通过并发修改与实际需求来平衡不同集合类型的特征和成本.你能不能看到迭代器没有看到所有并发修改?


dog*_*ane 11

考虑使用线程安全的CopyOnWriteArrayList.每次添加项目时,都会创建基础数组的新副本.但是,迭代器不会反映自迭代器创建以来对列表的添加,但保证不会抛出ConcurrentModificationException.

arrayList=new CopyOnWriteArrayList();
Run Code Online (Sandbox Code Playgroud)