关于集合类不安全的问题解决

关于集合类不安全的问题解决

List不安全

  • 通过List集合类在做一些基本的操作的时候,假设在并发的情况下执行会出现并发修改异常,也就是java.util.ConcurrentModificationException,其实不光是List集合,在Set和Map类使用的情况下同样也会出现这些问题
  • 对于List集合类,我们提供一些解决方案来解决并发修改异常的问题
    • List list = new Vector<>(); 也就是通过Vector来解决,这个类的底层是通过synchronized同步方法完成的 ,所以可以确保并发安全。
    • List list = Collections.synchronizedList(new ArrayList<>()),这套解决方案是由工具类Collections这个类底层调用的同步方法,本质也差不多,都是通过同步方法来解决并发下不安全的问题
    • List list = new CopyOnWriteArrayList<>(),这个是JUC包下的解决方案,CopyOnWrite是指写入时复制 也就是 COW,是计算机程序设计领域的一种优化策略。在多个线程调用的时候,list读取的时候是固定的,但是写入的时候会存在覆盖的情况,所以通过此方法解决,这种思想也是读写分离的思想,为的就是在写入的时候避免覆盖,造成一些数据的问题,它的底层是Lock锁,推荐使用。
  • 关于List不安全,我们推荐使用第三种解决方案,相比较 Vector来说,Lock锁一定比synchronized来的好一点,其具体区别可以看我的博客关于锁的运用,地址为https://blog.csdn.net/hzyzzz/article/details/106248265。接下来我展示一些测试List不安全的代码:
package com.czu.unsafe;

import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;

/**
 * java.util.ConcurrentModificationException 并发修改异常
 * @author 87682
 */
public class ListTest {
    public static void main(String[] args) {
//        List<String> list = Arrays.asList("1","2","3");
//        list.forEach(System.out::println);
        //并发下ArrayList是不安全的
        /**
         * 解决方案:
         * 1. List<String> list = new Vector<>();
         * 2. List<String> list = Collections.synchronizedList(new ArrayList<>());
         * 3. List<String> list = new CopyOnWriteArrayList<>();
         */
        //List<String> list = new ArrayList<>();
        // List<String> list = new Vector<>();
        //List<String> list = Collections.synchronizedList(new ArrayList<>());
        /**
         * CopyOnWrite是指写入时复制  COW  计算机程序设计领域的一种优化策略
         * 多个线程调用的时候,list,读取的时候,固定的,写入(覆盖)
         * 在写入的时候避免覆盖,造成数据问题
         * 读写分离
         * CopyOnWriteArrayList 比 Vector牛逼在哪里? Vector用的是synchronized CopyOnWriteArrayList用的是lock锁
         */

        List<String> list = new CopyOnWriteArrayList<>();
        for (int i = 1; i <= 10; i++) {
//            list.add(UUID.randomUUID().toString().substring(0,5));
//            System.out.println(list);
            new Thread(() -> {
                list.add(UUID.randomUUID().toString().substring(0, 5));
                System.out.println(list);
            }, String.valueOf(i)).start();

        }

    }
}

Set不安全

  • hashSet的底层其实就是hashMap,在并发情况下依旧会出现跟List一样的并发修改异常问题,解决方案相似:

    • Set set = Collections.synchronizedSet(new HashSet<>())
    • Set set = new CopyOnWriteArraySet<>()
  • 由于跟之前类似,我也不再多说,看代码:

import java.util.UUID;
import java.util.concurrent.CopyOnWriteArraySet;

/**
 * 同理可证: java.util.ConcurrentModificationException 并发修改异常
 * 解决方案:
 * 1. Set<String> set = Collections.synchronizedSet(new HashSet<>());
 * 2. Set<String> set = new CopyOnWriteArraySet<>();
 * @author 87682
 */
public class SetTest {
    public static void main(String[] args) {
        //Set<String> set = new HashSet<>();
        //Set<String> set = Collections.synchronizedSet(new HashSet<>());
        Set<String> set = new CopyOnWriteArraySet<>();
        for (int i = 1; i <= 30; i++) {
            new Thread(() -> {
                set.add(UUID.randomUUID().toString().substring(0, 5));
                System.out.println(set);
            }, String.valueOf(i)).start();
        }

    }
}

Map不安全

  • 其实在工作中我们一般不会去使用HashMap,原因也很简单,并发下的问题很大,它默认等价于new HashMap<>(16,0.75),两个参数分别为加载因子和初始化容量,正常情况下,我们会使用ConcurrentHashMap,代码如下:
package com.czu.unsafe;

import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;

/**
 * java.util.ConcurrentModificationException 并发修改异常
 * 研究ConcurrentHashMap的原理
 * @author 87682
 */
public class MapTest {
    public static void main(String[] args) {
        /**
         * map 是这样用的吗? 不是 ,工作中不用HashMap
         * 默认等价于什么?  new HashMap<>(16,0.75);
         * 加载因子 、 初始化容量
         */

        //Map<String,String> map = new HashMap<>();

        Map<String,String> map = new ConcurrentHashMap<>();
        for (int i = 1; i <= 30; i++) {
            new Thread(()->{
                map.put(Thread.currentThread().getName(), UUID.randomUUID().toString().substring(0, 5));
                System.out.println(map);
            },String.valueOf(i)).start();
        }

    }
}

总之多线程的并发下会产生很多问题,关于ConcurrentHashMap,这里没有过多解释,因为需要很多关于Map的基础,有兴趣的也可以研究一下它的源码,总之我提供了一些集合类不安全的解决方案,都是在JUC包下的方案,对于线程安全的问题应该很有帮助。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值