【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)
相关推荐
HBryce244 分钟前
缓存-基础概念
java·缓存
一只爱打拳的程序猿18 分钟前
【Spring】更加简单的将对象存入Spring中并使用
java·后端·spring
杨荧20 分钟前
【JAVA毕业设计】基于Vue和SpringBoot的服装商城系统学科竞赛管理系统
java·开发语言·vue.js·spring boot·spring cloud·java-ee·kafka
minDuck22 分钟前
ruoyi-vue集成tianai-captcha验证码
java·前端·vue.js
为将者,自当识天晓地。40 分钟前
c++多线程
java·开发语言
daqinzl1 小时前
java获取机器ip、mac
java·mac·ip
激流丶1 小时前
【Kafka 实战】如何解决Kafka Topic数量过多带来的性能问题?
java·大数据·kafka·topic
Themberfue1 小时前
Java多线程详解⑤(全程干货!!!)线程安全问题 || 锁 || synchronized
java·开发语言·线程·多线程·synchronized·
plmm烟酒僧1 小时前
Windows下QT调用MinGW编译的OpenCV
开发语言·windows·qt·opencv
newxtc1 小时前
【支付行业-支付系统架构及总结】
安全·支付宝·第三方支付·风控系统·财付通