JUC并发编程(三) : 不安全的集合类

不安全的集合类

并发环境下,我们经常使用的集合类(List、Map、Set)其实都是不安全的!
List
List在单线程的情况下是安全的,但是多线程的情况下是不安全的,我们来看两段代码:
单线程

public class UnsafeList1 {
    public static void main(String[] args) {
        List<String> list= Arrays.asList("a","b","c");
        list.forEach(System.out::println);
    }
}

在这里插入图片描述
多线程

public class UnsafeList2 {
    public static void main(String[] args) {
    
         ArrayList<Object> list=new ArrayList<>(); 
        for (int i = 1; i <=30; i++) {
            new Thread(()->{
                list.add(UUID.randomUUID().toString().substring(0,5));
                System.out.println(list);
            },String.valueOf(i)).start();

        }
    }
}

在这里插入图片描述
通过以上两段代码,我们可以看到,在多线程情况下会报ConcurrentModificationException(并发修改)异常,那我们如何去保证在多线程的情况下List的安全了,有以下三中方法:

  1. 使用Vector,我们都知道Vector是线程安全的。
public class UnsafeList2 {
    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,5));
                System.out.println(list);
            },String.valueOf(i)).start();

        }
    }
}

在这里插入图片描述
2.利用Collections类下的方法synchronizedList,将其变为安全的集合类。

public class UnsafeList2 {
    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,5));
                System.out.println(list);
            },String.valueOf(i)).start();

        }
    }
}

在这里插入图片描述
3. 使用CopyOnWriteArrayList。

public class UnsafeList2 {
    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,5));
                System.out.println(list);
            },String.valueOf(i)).start();

        }
    }
}

在这里插入图片描述
三种方式比较:
Vector
我们首先看下Vector和ArrayList的源码,
在这里插入图片描述
在这里插入图片描述
通过源码我们知道Vector在JDK1.0的时候就已经有了,而ArrayList是在JDK1.2才有的,不知道大家有没有想过这样一个问题,Vector既然已经处理了线程不安全的问题,为什么还有添加一个不安全的ArrayList呢?其实是有原因的,虽然实现了List接口,底层都是数组,但是Vector的性能却比ArrayList低。所以我们一般的话不采用Vector。

synchronizeList
通过源码分析,它是通过给自己本身暴力加锁而实现线程安全的,所以效率也比较低下,但是相对于Vector高点。

CopyOnWriteArrayList

CopyOnWriteArrayList其实利用了计算机领域的一个COW思想,多个调用者,想调用相同的资源,改变指针指向;在多线程下如果只是去读,就不会产生锁! 假如你是去写,就需要拷贝一份都自己哪里,修改完毕后,再替换指针!这样写的话保证数据的安全,效率也高,推荐使用!
在这里插入图片描述

Map
还是首先来一段代码:

public class UnsafeMap {
    public static void main(String[] args) {
      
     Map<String, String> map = new HashMap<>();
          
        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();
        }

    }
}


我们可以看到,HashMap是不安全的,解决方案就是使用HashTablehe和ConcurrentHashMap。HashTable效率低下,不建议使用!

Set

public class UnsafeSet1 {
    public static void main(String[] args) {
        Set<String> set =new HashSet<>();

        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();
        }

    }
}


Set的底层是HashMap,HashMap是不安全的,所以Set自然也是线程不安全的。解决方案就是synchronizedSet和CopyOnWriteSet。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值