同步ArrayList

时间:2013-11-16 01:21:59

标签: java arraylist synchronization

ArrayList api,我们有:

  

请注意,此实现未同步。如果有多个线程   同时访问一个ArrayList实例,并且至少有一个   线程在结构上修改列表,必须同步   外部。 (结构修改是添加或的任何操作   删除一个或多个元素,或显式调整后备数组的大小;   仅设置元素的值不是结构   修改。)这通常通过同步一些来完成   自然封装列表的对象。如果不存在这样的对象,   列表应该使用Collections.synchronizedList“包装”   方法

这里的意思是“这通常通过同步一些自然封装列表的对象来完成”?这与并发修改异常有何关系?

3 个答案:

答案 0 :(得分:8)

来自ArrayList

  

这通常通过同步自然封装列表的某个对象来完成。如果不存在这样的对象,那么   list应该使用Collections.synchronizedList“包装”   方法。这最好在创建时完成,以防止意外   对列表的非同步访问:

   List list = Collections.synchronizedList(new ArrayList(...));

通过“自然封装”意味着如果列表是对象的字段,但列表不可公开访问,请假设以下内容:

class ParkingLot{
   private ArrayList<Cars> spots;

   public boolean park(int spotNumber, Car car){          
       if( spots.get(spotNumber)==null){
            spot.set(spotNumber,car);
            return true;
       }
       return false;
   }
}

在这种情况下,ParkinLot会封装列表spot。如果您尝试呼叫park(),则需要在ParkingLot对象上进行同步,以防止两个线程同时将汽车停放在同一位置。

它与ConcurrentModificationException有关,因为它阻止你同时(通过同步)从单独的线程更改列表,这可能使列表处于不一致的状态(即两辆车停车同时思考他们已成功停车了。)

答案 1 :(得分:0)

为什么不使用Vector呢?它已经同步了。

答案 2 :(得分:0)

  

这里的意思是“这通常是通过同步完成的   在一些自然封装列表“

的对象上

如果您有一个封装ArrayList的类,那么如果您在包装器对象上进行同步,那么基础ArrayList也将是synchronized。例如

class MyClasss{

      private final ArrayList list;
      ......
      ......
      ......
 }

如果您在MyClass的实例上进行同步,那么基础列表也会同步,并且所有的读/写都将被序列化,例如

class MyClasss{

      private final ArrayList list;
      ......
      ......
      ......
      public void fun(){
          synchronized(this){
                list.add(....)
           }
 }

  

这与并发修改异常有何关系?   在回答上述问题之前,您需要了解JVM如何抛出ConcurrentModificationException

ConcurrentModificationException是通过检查每个Collection的修改计数在java中实现的。每次执行操作时,它都会在执行操作之前和执行操作之后比较修改计数。

因此,如果您synchronize Collection,则不会同时修改修改计数,导致不会抛出ConcurrentModificationException

希望它有所帮助。