Java JUC并发之集合类不安全问题

六、集合类不安全

List 不安全

package com.liu.unsafeListOrSet;

import com.liu.pc.A;
import java.util.*;
import java.util.concurrent.CopyOnWriteArrayList;

// java.util.ConcurrentModificationException 并发修改异常
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> list2 = Collections.synchronizedList(new ArrayList<>());
         * 3. List<String> list3 = new CopyOnWriteArrayList<>();
         */

        // List<String> list = new ArrayList<>();
        // List<String> list1 = new Vector<>();
        // List<String> list2 = Collections.synchronizedList(new ArrayList<>());
        // List<String> list3 = new CopyOnWriteArrayList<>();

        // CopyOnWrite 写入时复制  COW 计算机程序设计领域的一种优化策略
        // 多个线程调用的时候 list 读取的时候 => 固定 写入(覆盖)
        // 在写入的时候避免覆盖,造成数据问题! 写入时复制

        // 读写分离
        // CopyOnWrite(Lock) vs Vector (Synchronized) ? 好在哪里? 效率方面
        List<String> list3 = new CopyOnWriteArrayList<>();

        for (int i = 0; i < 10; i++) {
            new Thread(()->{
                // UUID 通用唯一识别码
                list3.add(UUID.randomUUID().toString().substring(0, 5));
                System.out.println(list3);
            },String.valueOf(i)).start();
        }
    }
}

Collections 类: 对集合进行操作的包装器

Collection.synchronizedList: 返回一个同步(线程安全)的List

Set不安全

package com.liu.unsafeListOrSet;

import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.CopyOnWriteArraySet;

// Set 同样不安全 : java.util.ConcurrentModificationException 并发修改异常

/**
 * 解决方案
 * 1. Set<String> set = Collections.synchronizedSet(new HashSet<>()); // 使用Collections
 * 2. Set<String> set = new CopyOnWriteArraySet<>(); // 使用CopyOnWriteSet
 */
public class SetTest {
    public static void main(String[] args) {

        // Set<String> set = new HashSet<>();
        // Set<String> set = Collections.synchronizedSet(new HashSet<>()); // 使用Collections
        Set<String> set = new CopyOnWriteArraySet<>(); // 使用CopyOnWriteSet
        for (int i = 1; i <= 3000; i++) {
            new Thread(()->{
                set.add(UUID.randomUUID().toString().substring(0, 5));
                System.out.println(set);
            },String.valueOf(i)).start();
        }
    }
}

HahSet 底层源码是什么?

本质: HashMap

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

add() Set 本质就是map, key是无法重复的

    public boolean add(E e) {
        return map.put(e, PRESENT)==null;
    }

private static final Object PRESENT = new Object(); // 不变的值

IO、 集合、 常用类

Map 不安全

HashMap: 加载因子 LoadFactor、初始容量 InitialCapacity

HashMap 的 put():

public V put(K key, V value) {
    return putVal(hash(key), key, value, false, true);
}

package com.liu.unsafeListOrSet;

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

public class MapTest {

    // java.util.ConcurrentModificationException 并发修改异常

    /**
     * 解决方案
     * 1. Collections
     * 2. new ConcurrentHashMap();
     * @param args
     */
    public static void main(String[] args) {

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

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

         Map<String, String> map = new ConcurrentHashMap<>(); // 并发的HashMap

        for (int i = 0; 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 原理 完全的并发性 + 高预期并发性 的 哈希表

posted @ 2021-07-15 16:51  夕立君  阅读(55)  评论(0编辑  收藏  举报