juc:集合类不安全

public class ListTest {
    public static void main(String[] args) {

        List<Object> arrayList = new ArrayList<>();

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

    }
}

会造成: 

ArrayList 在并发情况下是不安全的! 

解决方案:

1、切换成Vector就是线程安全的啦! 

2、使用Collections.synchronizedList(new ArrayList<>()); 

3、使用JUC中的包:List arrayList = new CopyOnWriteArrayList<>(); 

public class ListTest {
    public static void main(String[] args) {

        List<Object> arrayList = new CopyOnWriteArrayList<>();

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

    }
}

CopyOnWriteArrayList:写入时复制! COW 计算机程序设计领域的一种优化策略

多个线程调用的时候,list,读取的时候,固定的,写入(存在覆盖操作);在写入的时候避免覆盖,造成数据错乱的问题; 

CopyOnWriteArrayList比Vector厉害在哪里?

Vector底层是使用synchronized关键字来实现的:效率特别低下。 

CopyOnWriteArrayList使用的是Lock锁,效率会更加高效! 

Set不安全

和List、Set同级的还有一个BlockingQueue 阻塞队列; 

Set和List同理可得: 多线程情况下,普通的Set集合是线程不安全的;

解决方案还是两种:

  • 使用Collections工具类的synchronized包装的Set类
  • 使用CopyOnWriteArraySet 写入复制的JUC解决方案
//同理:java.util.ConcurrentModificationException
// 解决方案:
public class SetTest {
    public static void main(String[] args) {
//        Set<String> hashSet = Collections.synchronizedSet(new HashSet<>()); //解决方案1
        Set<String> hashSet = new CopyOnWriteArraySet<>();//解决方案2
        for (int i = 1; i < 100; i++) {
            new Thread(()->{
                hashSet.add(UUID.randomUUID().toString().substring(0,5));
                System.out.println(hashSet);
            },String.valueOf(i)).start();
        }
    }
}


HashSet底层是什么?

hashSet底层就是一个HashMap;

public HashSet() {
        map = new HashMap<>();
}

//add 本质其实就是一个map的key,map的key是无法重复的,所以使用的就是map存储
//hashSet就是使用了hashmap key不能重复的原理
public boolean add(E e) {
        return map.put(e, PRESENT)==null;
}
//PRESENT是什么? 是一个常量  不会改变的常量  无用的占位
private static final Object PRESENT = new Object();

Map不安全

回顾map的基本操作:

//map 是这样用的吗?  不是,工作中不使用这个
//默认等价什么? new HashMap<>(16,0.75);
Map<String, String> map = new HashMap<>();
//加载因子、初始化容量

默认加载因子是0.75,默认的初始容量是16

 

同样的HashMap基础类也存在并发修改异常

public static void main(String[] args) {
        //map 是这样用的吗?  不是,工作中不使用这个
        //默认等价什么? new HashMap<>(16,0.75);
        Map<String, String> map = new HashMap<>();
        //加载因子、初始化容量
        for (int i = 1; i < 100; i++) {
            new Thread(()->{
                map.put(Thread.currentThread().getName(),UUID.randomUUID().toString().substring(0,5));
                System.out.println(map);
            },String.valueOf(i)).start();
        }
    }

结果同样的出现了:异常java.util.ConcurrentModificationException 并发修改异常 

解决方案:

  • 使用Collections.synchronizedMap(new HashMap<>());处理;
  • 使用ConcurrentHashMap进行并发处理
  • TODO:研究ConcurrentHashMap底层原理:
    这里我们可以直接去研究一下,这个也是相当重要的。

猜你喜欢

转载自blog.csdn.net/s1623009261/article/details/120539729