【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)
相关推荐
Crossoads4 分钟前
【汇编语言】端口 —— 「从端口到时间:一文了解CMOS RAM与汇编指令的交汇」
android·java·汇编·深度学习·网络协议·机器学习·汇编语言
老马啸西风5 分钟前
NLP 中文拼写检测纠正论文-02-2019-SOTA FASPell Chinese Spell Checke github 源码介绍
java
向宇it7 分钟前
【从零开始入门unity游戏开发之——C#篇26】C#面向对象动态多态——接口(Interface)、接口里氏替换原则、密封方法(`sealed` )
java·开发语言·unity·c#·游戏引擎·里氏替换原则
@菜鸟进阶记@10 分钟前
java根据Word模板实现动态填充导出
java·开发语言
卖芒果的潇洒农民12 分钟前
Lecture 6 Isolation & System Call Entry
java·开发语言
代码改变世界ctw35 分钟前
如何学习Trustzone
安全·trustzone·atf·optee·tee·armv8·armv9
Amarantine、沐风倩✨1 小时前
设计一个监控摄像头物联网IOT(webRTC、音视频、文件存储)
java·物联网·音视频·webrtc·html5·视频编解码·七牛云存储
路在脚下@2 小时前
spring boot的配置文件属性注入到类的静态属性
java·spring boot·sql
森屿Serien2 小时前
Spring Boot常用注解
java·spring boot·后端
gywl3 小时前
openEuler VM虚拟机操作(期末考试)
linux·服务器·网络·windows·http·centos