集合类线程不安全问题

1 篇文章 0 订阅
1 篇文章 0 订阅

集合类线程不安全问题

一、ArrayList

  1. ArrayList底层是封装了数组,通过数组来存储数据的。当新建一个无参数的ArrayList时,new ArrayList() 的初始容量,在jdk1.6中的确是为10,然而在1.8中,如果只是new ArrayList() ,容量其实是0,当第一次通过add(E e)时,才扩充为10。

  2. 当ArrayList增加元素时,它是按照顺序从头部开始往后添加,它是有顺序的。

  3. .果当添加的元素超过当前数组的长度时,它会新创建一个数组,长度为当前数组的1.5倍,然后将当前数组的元素复制到新的数组,当前数组的内存被释放

    优点:操作读取操作效率高,基于数组实现的,可以为null值,可以允许重复元素,有序,异步。
    缺点:由于它是由动态数组实现的,不适合频繁的对元素的插入和删除操作,因为每次插入和删除都需 要移动数组中的元素。

原因:线程不安全,add方法没有用synchronized修饰。

public static void main(String[] args) {
        List<String> list = new ArrayList<>(); 
        // 1.List<String> list = new Vector();
        //2.List<String> list = Collections.synchronizedList(new ArrayList<>());
        //3.List<String> list = new CopyOnWriteArrayList<>();
        for (int i = 0; i < 20; i++) {
            new Thread(()->{
                list.add(UUID.randomUUID().toString().substring(0,5));
                System.out.println(list);
            },String.valueOf(i)).start();
        }

1.故障现象
java.util.ConcurrentModificationException 并发修改异常
2.导致原因
并发修改异常。 一个线程在写,另外线程进行抢夺,导致数据不一致异常。
3.解决方案
(1) new Vector()
(2) Collections.synchronizedList(new ArrayList<>())
(3) new CopyOnWriteArrayList<>(); 写时复制

CopyOnWrite容器即写时复制容器,往一个容器object[]中添加元素的时候, 先copy出一个新容器object[] newElements,再往新的容器里添加这个新的元素, 再将原容器的引用指向新的容器 setArray(newElements);
但是在添加这个数据的期间,其他线程如果要去读取数据, 仍然是读取到旧的容器里的数据。 这样做的好处是可以对CopyOnWrite容器并发的读,而不用加锁, 因为当前容器不会添加任何元素,所以CopyOnWrite也是读写分离的思想,读和写不同的容器。

二、HashSet

HashSet概述和实现

  1. HashSet 底层是HashMap 初始值16,加载因子为0.75。
  2. 在HashSet中,元素都存到HashMap键值对的Key上面,而Value时有一个统一的值private static final Object PRESENT = newObject(); (定义一个虚拟的Object对象作为HashMap的value,将此对象定义为static final。)
  3. Set不能有重复的元素,HashMap不允许有重复的键。

HashSet插入
当有新值加入时,底层的HashMap会判断Key值是否存在,如果不存在,则插入新值,同时这个插入的细节会依照HashMap插入细节;如果存在就不插入。

public static void main(String[] args) {
        Set<String> set = new HashSet<>(); 
        //和ArrayList 一样的两种方式保证 线程安全 
        // 1. Set<String> set = Collections.synchronizedSet(new HashSet<>());
        //2. Set<String> set = new CopyOnWriteArraySet<>();
        for (int i = 0; i < 20; i++) {
            new Thread(() -> {
                set.add(UUID.randomUUID().toString().substring(0, 5));
                System.out.println(set);
            }, String.valueOf(i)).start();
        }
    }

三、HashMap

HashMap与ConcurrentHashMap工作原理和区别

ConcurrentHashMap:在hashMap的基础上,ConcurrentHashMap将数据分为多个segment(段),默认16个(concurrency level),然后每次操作对一个segment(段)加锁,避免多线程锁的几率,提高并发效率。

具体可以查看 HashMap和ConcurrentHashMap区别

 public static void main(String[] args) {
        Map<String,String> map = new HashMap<>();  //线程不安全
        Map<String,String> ma1 = new ConcurrentHashMap<>(); //线程安全
        for (int i = 0; i < 20; i++) {
            new Thread(() -> {
                map.put(Thread.currentThread().getName(),UUID.randomUUID().toString().substring(0, 5));
                System.out.println(map);
            }, String.valueOf(i)).start();
        }
    }

侵权请告之,立马删除。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值