【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)
相关推荐
风象南7 分钟前
SpringBoot配置属性热更新的轻量级实现
java·spring boot·后端
洛阳泰山8 分钟前
Spring Boot 整合 Nacos 实战教程:服务注册发现与配置中心详解
java·spring boot·后端·nacos
Y4090018 分钟前
C语言转Java语言,相同与相异之处
java·c语言·开发语言·笔记
YuTaoShao10 分钟前
【LeetCode 热题 100】994. 腐烂的橘子——BFS
java·linux·算法·leetcode·宽度优先
布朗克16810 分钟前
java常见的jvm内存分析工具
java·jvm·数据库
都叫我大帅哥1 小时前
深入浅出 Resilience4j:Java 微服务的“免疫系统”实战指南
java·spring cloud
Cao_Shixin攻城狮3 小时前
Flutter运行Android项目时显示java版本不兼容(Unsupported class file major version 65)的处理
android·java·flutter
天天进步20155 小时前
前端安全指南:防御XSS与CSRF攻击
前端·安全·xss
Dcs6 小时前
还在用 Arrays.hashCode?Java 自己也能写出更快的版本!
java
fouryears_234178 小时前
Spring,Spring Boot 和 Spring MVC 的关系以及区别
java·spring boot·spring·mvc