【问题标题】:Synchronizing ArrayList同步 ArrayList
【发布时间】:2013-11-16 01:21:58
【问题描述】:

ArrayList api 我们有:

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

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

【问题讨论】:

  • 如果您同步访问对象,您将不会获得 CME。

标签: java arraylist synchronization


【解决方案1】:

来自ArrayList

这通常是通过同步一些自然封装列表的对象来完成的。如果不存在这样的对象,则 列表应该使用 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 相关,因为它阻止您同时从单独的线程更改列表(通过同步),这可能会使列表处于不一致的状态(即,两辆车同时停放,认为他们'已成功停车)。

【讨论】:

    【解决方案2】:

    这里所说的“这通常是通过同步来完成的 在一些自然封装列表的对象上"

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

    class MyClasss{
    
          private final ArrayList list;
          ......
          ......
          ......
     }
    

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

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

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

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

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

    希望对你有帮助。

    【讨论】:

    • 由于对 modCount 的访问不同步,如果您从多个线程访问 arraylist 而没有同步,甚至可能不会抛出 ConcurrentModificationException
    【解决方案3】:

    为什么不改用Vector?已经同步了。

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-03
    • 2012-08-05
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多