在ArrayList
api,我们有:
请注意,此实现未同步。如果有多个线程 同时访问一个ArrayList实例,并且至少有一个 线程在结构上修改列表,必须同步 外部。 (结构修改是添加或的任何操作 删除一个或多个元素,或显式调整后备数组的大小; 仅设置元素的值不是结构 修改。)这通常通过同步一些来完成 自然封装列表的对象。如果不存在这样的对象, 列表应该使用Collections.synchronizedList“包装” 方法
这里的意思是“这通常通过同步一些自然封装列表的对象来完成”?这与并发修改异常有何关系?
答案 0 :(得分:8)
这通常通过同步自然封装列表的某个对象来完成。如果不存在这样的对象,那么 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
。
希望它有所帮助。