并发修改异常(ArrayList)
ArrayList不安全
原因:
是由于高并发下add方法没有加锁,该方法不安全
引发:
java.util.ConcurrentModificationException
高并发修改异常
代码Demo
public class ContainerNotSafeDemo{
public static void main(Stirng[] args){
List<String> list=new ArrayList<>();
for(int i=1;i<30;i++){
new Thread(()->{
list.add(UUID.randomUUID().toString().subString(0,8));
System.out.println(list);
},String.valueOf(i).start());
}
}
}
解决方案:
1)使用Vector方法替换ArrayList方法,因为Vector的add方法加了锁syncronized
new Vector<>()
2)使用Collections的工具类:
Collections.syncronizedList(new ArrayList<>())
补充:Collection代表接口,而Collections表示集成接口的辅助工具类
3)使用写时复制,也就是读写分离
CopyOnWriteArrayList
CopyOnWrite容器即写时复制的容器。往一个容器添加元素的时候,不直接往当前容器Object[]添加,而是先将当前容器Object[]进行Copy,复制出一个新的容器Object[] newElements,然后心得容器Object[] newElements里添加元素,添加完元素之后,再将原容器得引用指向新的容器setArray(newElements)。
这样做得好处是可以对CopyOnWrite容器进行并发的读,而不需要加锁,因为当前容器不会添加任何元素。所以CopyOnWrite容器也是一种读写分离的思想,读和写在不同的容器
Set
ArraySet也是不安全的类,就像ArrayList一样。解决方案也相同有3个,第二个用的是Collections.syncronizedSet()
,第三个Set的读写分离用的是CopyOnwriteArraySet()
方法。但是CopyOnwriteArraySet()
的底层实现仍然是CopyOnwriteArrayList()
常见面试题:
HashSet的底层是什么?
HashSet的底层是HashMap
而Set的add方法只有一个值的原因:
Set的add调用的方法还是map.put,add的传值就是put的key,而put的value是一个常量Present
Map
与上面2个一样都是不安全的,new HashMap<>().put
(xx,xx)不安全
使用Collections.syncronizedMap()
有一定不同的是,第三种方法使用的是new ConcurrentHashMap<>()