【JUC并发编程】集合类安全问题

一、并发下,ArrayList类是不安全的

  • 代码演示
    package CollectionSafe;
    
    import java.util.ArrayList;
    import java.util.List;
    import java.util.UUID;
    
    /**
     * @author swaggyhang
     * @create 2023-07-02 17:26
     */
    public class Test01 {
        public static void main(String[] args) {
            List<String> list = new ArrayList<>();
            for (int i = 1; i <= 10; i++) {
                new Thread(() -> {
                    list.add(UUID.randomUUID().toString().substring(0, 5));
                    System.out.println(list);
                }, String.valueOf(i)).start();
            }
        }
    }
    
  • 上面代码会报错并发修改异常“java.util.ConcurrentModificationException”

二、解决方案

1. 使用Vector类【不推荐】

  • Vector类的add方法是同步方法,但是效率很低
    【JUC并发编程】集合类安全问题_第1张图片
  • 代码演示
    package CollectionSafe;
    
    import java.util.List;
    import java.util.UUID;
    import java.util.Vector;
    
    /**
     * @author swaggyhang
     * @create 2023-07-02 17:26
     */
    public class Test01 {
        public static void main(String[] args) {
    //        List list = new ArrayList<>();
            List<String> list = new Vector<>();
            for (int i = 1; i <= 10; i++) {
                new Thread(() -> {
                    list.add(UUID.randomUUID().toString().substring(0, 5));
                    System.out.println(list);
                }, String.valueOf(i)).start();
            }
        }
    }
    

2. 使用Collections工具类

  • 使用Collections.synchronizedList()方法将普通的ArrayList类转换为安全的集合类
    【JUC并发编程】集合类安全问题_第2张图片

  • 代码演示

    package CollectionSafe;
    
    import java.util.ArrayList;
    import java.util.Collections;
    import java.util.List;
    import java.util.UUID;
    
    /**
     * @author swaggyhang
     * @create 2023-07-02 17:26
     */
    public class Test01 {
        public static void main(String[] args) {
    //        List list = new ArrayList<>();
    //        List list = new Vector<>();
            List<String> list = Collections.synchronizedList(new ArrayList<>());
            for (int i = 1; i <= 10; i++) {
                new Thread(() -> {
                    list.add(UUID.randomUUID().toString().substring(0, 5));
                    System.out.println(list);
                }, String.valueOf(i)).start();
            }
        }
    }
    

3. 使用CopyOnWriteArrayList类

  • 写入时复制(简称:COW)是计算机领域的一种优化策略。底层源码如下:
    【JUC并发编程】集合类安全问题_第3张图片

  • 多线程调用list时,读取的时候,是固定的,写入的时候,避免覆盖,造成数据问题(类似读写分离)

  • add()方法源码
    【JUC并发编程】集合类安全问题_第4张图片

  • 代码演示

    package CollectionSafe;
    
    import java.util.List;
    import java.util.UUID;
    import java.util.concurrent.CopyOnWriteArrayList;
    
    /**
     * @author swaggyhang
     * @create 2023-07-02 17:26
     */
    public class Test01 {
        public static void main(String[] args) {
    //        List list = new ArrayList<>();
    //        List list = new Vector<>();
    //        List list = Collections.synchronizedList(new ArrayList<>());
            List<String> list = new CopyOnWriteArrayList<>();
            for (int i = 1; i <= 10; i++) {
                new Thread(() -> {
                    list.add(UUID.randomUUID().toString().substring(0, 5));
                    System.out.println(list);
                }, String.valueOf(i)).start();
            }
        }
    }
    

三、并发下,HashSet类是不安全的

  • HashSet本质就是HashMap,其构造器生成一个map对象【JUC并发编程】集合类安全问题_第5张图片

  • add()方法源码
    【JUC并发编程】集合类安全问题_第6张图片

  • 代码演示

    package CollectionSafe;
    
    import java.util.HashSet;
    import java.util.Set;
    import java.util.UUID;
    
    /**
     * @author swaggyhang
     * @create 2023-07-04 10:42
     */
    public class Test02 {
        public static void main(String[] args) {
            Set<String> set = new HashSet<>();
            for (int i = 1; i <= 100; i++) {
                new Thread(() -> {
                    set.add(UUID.randomUUID().toString().substring(0, 5));
                    System.out.println(set);
                }, String.valueOf(i)).start();
            }
        }
    }
    
  • 上面代码会报错并发修改异常“java.util.ConcurrentModificationException”

四、解决方案

1. 使用Collections工具类

  • 使用Collections.synchronizedSet()方法将普通的HashSet类转换为安全的集合类

    package CollectionSafe;
    
    import java.util.Collections;
    import java.util.HashSet;
    import java.util.Set;
    import java.util.UUID;
    
    /**
     * @author swaggyhang
     * @create 2023-07-04 10:42
     */
    public class Test02 {
        public static void main(String[] args) {
    //        Set set = new HashSet<>();
            Set<String> set = Collections.synchronizedSet(new HashSet<>());
            for (int i = 1; i <= 100; i++) {
                new Thread(() -> {
                    set.add(UUID.randomUUID().toString().substring(0, 5));
                    System.out.println(set);
                }, String.valueOf(i)).start();
            }
        }
    }
    

2. 使用CopyOnWriteArraySet类

  • CopyOnWriteArraySet底层还是使用CopyOnWriteArrayList那一套逻辑
    package CollectionSafe;
    
    import java.util.Set;
    import java.util.UUID;
    import java.util.concurrent.CopyOnWriteArraySet;
    
    /**
     * @author swaggyhang
     * @create 2023-07-04 10:42
     */
    public class Test02 {
        public static void main(String[] args) {
    //        Set set = new HashSet<>();
    //        Set set = Collections.synchronizedSet(new HashSet<>());
            Set<String> set = new CopyOnWriteArraySet<>();
            for (int i = 1; i <= 100; i++) {
                new Thread(() -> {
                    set.add(UUID.randomUUID().toString().substring(0, 5));
                    System.out.println(set);
                }, String.valueOf(i)).start();
            }
        }
    }
    
  • 构造器源码
    【JUC并发编程】集合类安全问题_第7张图片
  • add()方法源码
    【JUC并发编程】集合类安全问题_第8张图片

五、并发下,HashMap类是不安全的

  • 代码演示

    package CollectionSafe;
    
    import java.util.HashMap;
    import java.util.Map;
    import java.util.UUID;
    
    /**
     * @author swaggyhang
     * @create 2023-07-04 11:08
     */
    public class Test03 {
        public static void main(String[] args) {
            Map<String, String> map = new HashMap<>();
            for (int i = 1; i <= 10; 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”

六、解决方案

1. 使用Collections工具类

  • 使用Collections.synchronizedMap()方法将普通的HashMap类转换为安全的集合类
    package CollectionSafe;
    
    import java.util.Collections;
    import java.util.HashMap;
    import java.util.Map;
    import java.util.UUID;
    
    /**
     * @author swaggyhang
     * @create 2023-07-04 11:08
     */
    public class Test03 {
        public static void main(String[] args) {
    //        Map map = new HashMap<>();
            Map<String, String> map = Collections.synchronizedMap(new HashMap<>());
            for (int i = 1; i <= 10; i++) {
                new Thread(() -> {
                    map.put(Thread.currentThread().getName(), UUID.randomUUID().toString().substring(0, 5));
                    System.out.println(map);
                }, String.valueOf(i)).start();
            }
        }
    }
    

2. 使用ConcurrentHashMap类

  • 代码演示

    package CollectionSafe;
    
    import java.util.Map;
    import java.util.UUID;
    import java.util.concurrent.ConcurrentHashMap;
    
    /**
     * @author swaggyhang
     * @create 2023-07-04 11:08
     */
    public class Test03 {
        public static void main(String[] args) {
    //        Map map = new HashMap<>();
    //        Map map = Collections.synchronizedMap(new HashMap<>());
            Map<String, String> map = new ConcurrentHashMap<>();
            for (int i = 1; i <= 10; i++) {
                new Thread(() -> {
                    map.put(Thread.currentThread().getName(), UUID.randomUUID().toString().substring(0, 5));
                    System.out.println(map);
                }, String.valueOf(i)).start();
            }
        }
    }
    
  • 研究ConcurrentHashMap底层源码!!

你可能感兴趣的:(JUC并发编程,java)