【Java集合类不安全示例】

文章目录


提示:以下是本篇文章正文内容,下面案例可供参考

一、List

代码如下(示例):

java 复制代码
public class ZZZZZZZZZZ {
    public static void main(String[] args) {
        // ArrList 非线程安全的集合
        List<String> list1 = new ArrayList<>();
        
        for (int i = 0; i < 30; i++) {
            new Thread(() -> {// 多个线程同时向 ArrayList 添加元素
                list1.add(UUID.randomUUID().toString().substring(0, 8));
                System.out.println(list1);
            }).start();
        }
    }
}

输出结果

Exception in thread "Thread-1" Exception in thread "Thread-0" Exception in thread "Thread-4" Exception in thread "Thread-25" Exception in thread "Thread-23" Exception in thread "Thread-17" Exception in thread "Thread-18" Exception in thread "Thread-27" java.util.ConcurrentModificationException并发修改异常,由于ArrayList 不是线程安全的容器,多个线程并发添加元素,会导致竞争现象,最终产生该异常

故障出现

java.util.ConcurrentModificationException

导致原因

多线程并发争抢修改导致

解决方法

  • 使用线程安全的容器,例如:Vector,在该类中每个方法都加上了 synchronized,不会导致线程安全问题,但是由于锁的粒度太细,会导致程序的速度较慢。
  • 使用集合工具类的线程安全的方法,如:
java 复制代码
static <T> List<T> Collections.synchronizedList(List<T> list)
  • juc 下面的 CopyOnWriteArrayList,该类使用使用 ReentrantLock 加锁解锁,每次添加新元素就会加锁,然后开辟比旧数组多1的空间,将原数组全部拷贝进去,再将新元素加到最后一个位置。由于每次添加元素都会拷贝原数组,如果原数组很大,就会对内存资源造成很大的消耗,因此适合读多写少的场景。源码如下:
java 复制代码
             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();
                  }
              }

二、Set

代码如下(示例):

java 复制代码
public class ZZZZZZZZZZ {
    public static void main(String[] args) {
        // 非线程安全的 HashSet
        Set<String> set = new HashSet<>();
        for (int i = 0; i < 30; i++) {
            new Thread(() -> {
                set.add(UUID.randomUUID().toString().substring(0, 8));
                System.out.println(set);
            }).start();
        }
    }
}

故障出现

java.util.ConcurrentModificationException

导致原因

多线程并发争抢修改导致

解决方法

  • 使用集合工具类的线程安全的方法,如:
java 复制代码
static <T> Set<T> Collections.synchronizedList(Set<T> s)
  • juc 下面的 CopyOnWriteArraySet,底层还是 CopyOnWriteArrayList,源码的构造方法如下:
java 复制代码
    public CopyOnWriteArraySet() {
        al = new CopyOnWriteArrayList<E>();
    }

三、Map

代码如下(示例):

java 复制代码
public class ZZZZZZZZZZ {
    public static void main(String[] args) {
        // 非线程安全的 HashMap
        Map<String, String> map = new HashMap<>();
        for (int i = 0; i < 30; i++) {
            new Thread(() -> {
                map.put(Thread.currentThread().getName(), UUID.randomUUID().toString().substring(0, 8));
                System.out.println(map);
            }).start();
        }
    }
}

故障出现

java.util.ConcurrentModificationException

导致原因

多线程并发争抢修改导致

解决方法

  • 使用线程安全的容器,如:ConcurrentHashMap

  • 使用集合工具类的线程安全的方法,如:

java 复制代码
static <K, V> Map<K, V> Collections.synchronizedMap(Map<K, V> m)
相关推荐
llwszx3 小时前
深入理解Java锁原理(一):偏向锁的设计原理与性能优化
java·spring··偏向锁
芳草萋萋鹦鹉洲哦3 小时前
【vue3+tauri+rust】如何实现下载文件mac+windows
windows·macos·rust
李洋-蛟龙腾飞公司3 小时前
HarmonyOS NEXT应用元服务常见列表操作多类型列表项场景
windows
安全系统学习3 小时前
【网络安全】Mysql注入中锁机制
安全·web安全·网络安全·渗透测试·xss
云泽野3 小时前
【Java|集合类】list遍历的6种方式
java·python·list
二进制person4 小时前
Java SE--方法的使用
java·开发语言·算法
小阳拱白菜5 小时前
java异常学习
java
FrankYoou6 小时前
Jenkins 与 GitLab CI/CD 的核心对比
java·docker
麦兜*6 小时前
Spring Boot启动优化7板斧(延迟初始化、组件扫描精准打击、JVM参数调优):砍掉70%启动时间的魔鬼实践
java·jvm·spring boot·后端·spring·spring cloud·系统架构
KK溜了溜了7 小时前
JAVA-springboot 整合Redis
java·spring boot·redis