java.util.concurrentModificationExection 并发修改异常

Posted on 2019-09-23 02:37  MrEven  阅读(265)  评论(0)    收藏  举报

多线程环境下线程不安全的集合类

ArrayList、HashSet、 HashMap....

解决方案:

ArrayList多线程环境下导致并发修改异常的解决方法:

1、使用 new  Vector<>(),因为Vector中的add()方法添加了synchronize的同步关键字,所以在多线程环境下可以解决并发修改异常,但会导致并发量下降。

2、使用Collections.synchronizeList(new ArrayList<>()),也可以解决并发修改异常

3、使用new CopyOnWriteArrayList<>(),写实复制的(读写分离的思想)

写时复制:

CopyOnWrite 容器即写时复制的容器,往一个容器添加元素的时候,不直接往当前的容器Object[]添加,而是先将当前的容器Object[]进行Copy,复制出一个新的容器Object[] newElements,然后往新的容器Object[] newElements 里面添加元素,添加完元素之后,再将原容器的引用指向新的容器setArray(newElements);这样做的好处是可以对CopyOnWrite容器进行并发的读,而不需要加锁,因为当前的容器不会添加任何元素。所以CopyOnWrite 容器也是 “一种读写分离的思想”,读和写不同的容器。

源码解析如下:

 

 1  public boolean add(E e) {
 2             final ReentrantLock lock = this.lock;
 3             lock.lock();
 4             try {
 5                 Object[] elements = getArray();
 6                 int len = elements.length;//获取原容器的长度(大小)
 7                 Object[] newElements = Arrays.copyOf(elements, len + 1);//复制一个新的Object 容器
 8                 newElements[len] = e;//往新的Object容器中添加元素
 9                 setArray(newElements);//将原容器的引用指向新容器
10                 return true;
11             } finally {
12                 lock.unlock();
13  }
View Code

 

多线程环境下集合类不安全问题的小case,以及解决方法。

 1 package com.company.array.demo;
 2 
 3 import java.util.*;
 4 import java.util.concurrent.ConcurrentHashMap;
 5 import java.util.concurrent.CopyOnWriteArrayList;
 6 import java.util.concurrent.CopyOnWriteArraySet;
 7 
 8 /**
 9  * 集合类不安全的问题
10  * ArrayList
11  * HashSet 
12  * Map
13  *java.util.ConcurrentModificationException 常用集合类多线程下并发 
14  *修改异常的解决方案。
15  */
16 public class ContainerNotSafeDemo {
17     public static void main(String[] args) {
18         listNotSafe();
19         setNotSafe();
20         mapNotSafe();
21     }
22 
23     //解决HashMap多线程下面并发修改异常的方法
24     public static void mapNotSafe() {
25         /*Map<String, String> map = new HashMap<>();*/ //并发修改异常
26         /*Map<String, String> map = Collections.synchronizedMap(new HashMap<>());*//方案一
27         Map<String, String> map = new ConcurrentHashMap<>();//方案二
28         for (int i = 1; i <= 30; i++) {
29             new Thread(() -> {
30                 map.put(Thread.currentThread().getName(), UUID.randomUUID().toString().substring(0, 8));
31                 System.out.println(map);
32             }, String.valueOf(i)).start();
33         }
34     }
35 
36     //解决HashSet多线程下面并发修改异常的方法
37     public static void setNotSafe() {
38         /*Set<String> set = new HashSet<>();*///多线程下线程不安全。并发修改异常
39         /*Set<String>  set= Collections.synchronizedSet(new HashSet<>());*//方案一
40         Set<String> set = new CopyOnWriteArraySet<>();// 方案二
41         for (int i = 1; i <= 30; i++) {
42             new Thread(() -> {
43                 set.add(UUID.randomUUID().toString().substring(0, 8));
44                 System.out.println(set);
45             }, String.valueOf(i)).start();
46         }
47     }
48 
49     //解决ArrayList多线程下面并发修改异常的方法
50     public static void listNotSafe() {
51         /*List<String> list1 = new Vector<>();*///方案一
52         /*List<String> list2 = Collections.synchronizedList(new ArrayList<>());*///方案二
53         List<String> list = new CopyOnWriteArrayList<>();//方案三
54         for (int i = 1; i <= 10; i++) {
55             new Thread(() -> {
56                 list.add(UUID.randomUUID().toString().substring(0, 8));
57                 System.out.println(list);
58             }, String.valueOf(i)).start();
59         }
60     }
61 }
View Code

 

博客园  ©  2004-2026
浙公网安备 33010602011771号 浙ICP备2021040463号-3