集合 安全 問題
-
集合不安全現象
- ArrayList、HashSet、HashMap在迭代的時候如果同時對其進行修改就會、拋出java.util.ConcurrentModificationException異常(併發修改異常)
List<String> list = new ArrayList<>();//線程不安全 Set<String> set = new HashSet<>();//線程不安全 Map<String,String> map = new HashMap<>();//線程不安全 for (int i = 0; i <30 ; i++) { new Thread(()->{ list.add(UUID.randomUUID().toString().substring(0,8)); System.out.println(list); },String.valueOf(i)).start(); }
-
ArrayList原因分析
ArrayList的源碼add()方法中沒有synchronized、線程不安全public boolean add(E e) { ensureCapacityInternal(size + 1); // Increments modCount!! elementData[size++] = e; return true; }
-
解決方案
-
換成線程安全的Vector()方法、Vector的源碼中add()方法有synchronized、線程安全
//List<String> list = new Vector<>(); public synchronized boolean add(E e) { modCount++; ensureCapacityHelper(elementCount + 1); elementData[elementCount++] = e; return true; }
-
利用Collections提供了方法**Collections.synchronizedList()**保證list是同步線程安全的
List<String> list = Collections.synchronizedList(new ArrayList<>()); for (int i = 0; i <30 ; i++) { new Thread(()->{ list.add(UUID.randomUUID().toString().substring(0,8)); System.out.println(list); },String.valueOf(i)).start(); }
-
使用寫時複製、**CopyOnWriteArrayList()**是Arraylist的一種線程安全變體,其中所有可變操作(add、set等)都是通過生成底層Object[ ]數組的新副本來實現的。
//List<String> list = new CopyOnWriteArrayList<>(); //底層源碼 public boolean add(E e) { final ReentrantLock lock = this.lock; lock.lock(); try { Object[] elements = getArray(); int len = elements.length; Object[] newElements = Arrays.copyOf(elements, len + 1); newElements[len] = e; setArray(newElements); return true; } finally { lock.unlock(); } }
- CopyOnWrite容器即寫時複製的容器。往一個容器添加元素的時候,不直接往當前容器Object[]添加,而是先將當前容器Object[]進行Copy,複製出一個新的容器Object[] newElements,然後向新的容器Object[] newElements裏添加元素。
添加元素後,再將原容器的引用指向新的容器setArray(newElements)。
這樣做的好處是可以對CopyOnWrite容器進行併發的讀,而不需要加鎖,因爲當前容器不會添加任何元素。
所以CopyOnWrite容器也是一種讀寫分離的思想,讀和寫使用不同的容器。
- CopyOnWrite容器即寫時複製的容器。往一個容器添加元素的時候,不直接往當前容器Object[]添加,而是先將當前容器Object[]進行Copy,複製出一個新的容器Object[] newElements,然後向新的容器Object[] newElements裏添加元素。
-
-
與ArrayList相類比,HashSet和HashMap也有寫時複製:
Set<String> set = new HashSet<>();//線程不安全 Set<String> set = new CopyOnWriteArraySet<>();//線程安全 Map<String,String> map = new HashMap<>();//線程不安全 Map<String,String> map = new ConcurrentHashMap<>();//線程安全