高并发下如何保证集合的安全

目录

模拟出异常

控制台输出的Concurrent(并发)Modification(更改)Exception异常信息

解决方案一、new Vector<>();

上代码

控制台输出(达到线程安全目的)

为什么呢?

解决方案二、java.util.Collections.synchronizedXXX();

上代码

控制台输出(达到线程安全目的)

为什么?

举一反三

解决方案三(主角)、new CopyOnWriteArrayList<>();

上代码

控制台输出(达到线程安全目的)

为什么?

举一反三


众所周知,ArrayList,HashMap,HashSet...是不安全的,本文章主要拿ArrayLisy做演示,同时也会提到其他的集合类如何创建。

模拟出异常

    public static void main(String[] args) {
        List<String> list = new ArrayList<>();

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

控制台输出的Concurrent(并发)Modification(更改)Exception异常信息

[64ecee, 217e9b, 21a8d4, 73978f, a30e8e, 5643ed, 4af994, b8ff61, 89d4ab, 8fa982, 87a8d2, 5311c0, ebdebb, 696d1c, cc089f, 4c258b, 2d573f, 4d8b43, 070db7]
Exception in thread "4" Exception in thread "3" Exception in thread "2" Exception in thread "1" java.util.ConcurrentModificationException
    at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:909)
    at java.util.ArrayList$Itr.next(ArrayList.java:859)
    at java.util.AbstractCollection.toString(AbstractCollection.java:461)
    at java.lang.String.valueOf(String.java:2994)
    at java.io.PrintStream.println(PrintStream.java:821)
    at cr.example.demo.Test.lambda$main$0(Test.java:17)
    at java.lang.Thread.run(Thread.java:748)
java.util.ConcurrentModificationException
    at java.util.ArrayList$Itr.checkForComodification(ArrayList.java:909)

解决方案一、new Vector<>();

上代码

 public static void main(String[] args) {
        List<String> list = new Vector<>();

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

控制台输出(达到线程安全目的)

为什么呢?

点进去源码看,原来Vector的add方法时加了锁的(synchronized),所以证明是线程安全的。

解决方案二、java.util.Collections.synchronizedXXX();

上代码

    public static void main(String[] args) {
        List<String> list = Collections.synchronizedList(new ArrayList<>());

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

控制台输出(达到线程安全目的)

为什么?

一层一层点进源码,可以看出来增删改查方法都加上了synchronized

举一反三

除了有Collections.synchronizedList肯定也有Collections.synchronizedMap,Collections.synchronizedSet。。。如下图

解决方案三(主角)、new CopyOnWriteArrayList<>();

上代码

public static void main(String[] args) {
        List<String> list = new CopyOnWriteArrayList<>();

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

控制台输出(达到线程安全目的)

为什么?

进去源码里面瞧一瞧

首先可以看到他的add方法是加了锁的,最厉害的是CopyOnWriteArrayList用了读写分离的理念,请跟着我下面的注释思路

 /**
     * Appends the specified element to the end of this list.
     *
     * @param e element to be appended to this list
     * @return {@code true} (as specified by {@link Collection#add})
     */
    public boolean add(E e) {
        final ReentrantLock lock = this.lock;
        //1、添加锁
        lock.lock();
        try {
        //2、获取到“当前数组”
            Object[] elements = getArray();
        //3、获取到“当前数组”的长度
            int len = elements.length;
        //4、拷贝出一个比“当前数据”长度+1的“新数组”
            Object[] newElements = Arrays.copyOf(elements, len + 1);
        //5、在“新数组”的最后位置添加上元素,所以插入数据是在“新数组”,查看数据是在“当前数组”
            newElements[len] = e;
        //6、然后将更改好的“新数组”替换为“当前数组”
            setArray(newElements);
            return true;
        } finally {
        //7、解锁
            lock.unlock();
        }
    }

举一反三

   new CopyOnWriteArrayList<>(),new CopyOnWriteArraySet<>(),

   new ConcurrentHashMap<>() 。。。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java高并发线程安全集合是指在多线程环境下能够保证数据一致性和线程安全的数据结构。Java提供了许多高并发线程安全集合,包括ConcurrentHashMap、ConcurrentSkipListMap、ConcurrentSkipListSet、CopyOnWriteArrayList、CopyOnWriteArraySet等。 ConcurrentHashMap是一个线程安全的哈希表,它允许多个线程同时读取并修改其中的元素。它使用分段锁的方式来实现并发访问,不同的线程可以同时访问不同的分段,从而提高了并发性能。 ConcurrentSkipListMap是一个基于跳表的并发有序映射,它可以提供较好的并发性能,且支持按照键的顺序进行遍历。它的实现是通过通过多层链表实现的,每一层链表中的节点按照键的顺序排列。 ConcurrentSkipListSet是一个基于ConcurrentSkipListMap的并发有序集合,它实现了Set接口,并且保证元素的有序性和线程安全性。 CopyOnWriteArrayList是一个线程安全的ArrayList,它通过每次修改时创建一个新的副本来实现线程安全。虽然在插入和删除操作时需要复制整个数组,但读取操作非常高效,适用于读操作远多于写操作的场景。 CopyOnWriteArraySet是一个线程安全的Set,它是基于CopyOnWriteArrayList实现的。它通过复制整个数组来实现线程安全保证了元素的唯一性和线程安全。 这些高并发线程安全集合在多线程环境中保证了数据的一致性和线程安全性,能够提高并发性能和效率,适用于高度并发和需要频繁读写的场景。但需要注意的是,并发集合在某些操作上可能会损失一些性能,因此在选择使用时需根据具体需求进行权衡和选择。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值