我们知道ArrayList是线程不安全,请编码写一个不安全的案例并给出解决方案。

解决方案 1

package com.brian.interview.study.thread;

/**
 * Copyright (c) 2020 ZJU All Rights Reserved
 * <p>
 * Project: JavaSomeDemo
 * Package: com.brian.interview.study.thread
 * Version: 1.0
 * <p>
 * Created by Brian on 2020/2/11 18:13
 */

import java.util.*;

/**
 * 集合类不安全的问题
 *   ArrayList
 */
public class ContainerNotSafeDemo {

    public static void main(String[] args) {

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

        for (int i = 1; i <= 30; i++) {
            new Thread(() -> {
                list.add(UUID.randomUUID().toString().substring(0, 8));
                System.out.println(list);
            }, String.valueOf(i)).start();
        }
        // java.util.ConcurrentModificationException

        /**
         * 1、故障现象
         *        java.util.ConcurrentModificationException
         *
         * 2、导致原因
         *
         * 3、解决方案
         *     3.1、new Vector<>();
         *     3.2、Collections.synchronizedList(new ArrayList<>());
         *     3.3、???
         *
         * 4、优化建议(同样的错误不犯第2次)
         *
         */
    }

}

限制不可以用 Vector 和 Collections 工具类解决方案 2

CopyOnWriteArrayList

package com.brian.interview.study.thread;

/**
 * Copyright (c) 2020 ZJU All Rights Reserved
 * <p>
 * Project: JavaSomeDemo
 * Package: com.brian.interview.study.thread
 * Version: 1.0
 * <p>
 * Created by Brian on 2020/2/11 18:13
 */

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.CopyOnWriteArraySet;

/**
 * 集合类不安全的问题
 *   ArrayList
 */
public class ContainerNotSafeDemo {

    public static void main(String[] args) {

    }

    private static void mapNoSafe() {
        //Map<String, String> map = new HashMap<>();
        //Map<String, String> map = Collections.synchronizedMap(new HashMap<>());
        Map<String, String> map = new ConcurrentHashMap<>();
        for (int i = 1; i <= 30; i++) {
            new Thread(() -> {
                map.put(Thread.currentThread().getName(), UUID.randomUUID().toString().substring(0, 8));
                System.out.println(map);
            }, String.valueOf(i)).start();
        }
    }

    private static void setNoSafe() {
        //Set<String> set = new HashSet<>();
        //Set<String> set = Collections.synchronizedSet(new HashSet<>());
        Set<String> set = new CopyOnWriteArraySet<>();
        for (int i = 1; i <= 30; i++) {
            new Thread(() -> {
                set.add(UUID.randomUUID().toString().substring(0, 8));
                System.out.println(set);
            }, String.valueOf(i)).start();
        }
        new HashSet<>().add("a");
        /**
         * HashSet底层是HashMap:
         * Constructs a new, empty set; the backing <tt>HashMap</tt> instance has
         * default initial capacity (16) and load factor (0.75).
         *
         * add方法也是调用map的put方法   键为HashSet的值, 值为一个Object常量
         */
    }

    public static void listNotSafe() {
        //List<String> list = new Vector<>();
        //List<String> list = Collections.synchronizedList(new ArrayList<>());
        List<String> list = new CopyOnWriteArrayList<>();

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

        // java.util.ConcurrentModificationException

        /**
         * 1、故障现象
         *        java.util.ConcurrentModificationException
         *
         * 2、导致原因
         *     并发争抢修改导致, 参考我们的花名册签名情况。
         *     一个人正在写入, 另外一个同学过来抢夺, 导致数据不一致异常。并发修改异常。
         *
         * 3、解决方案
         *     3.1、new Vector<>();
         *     3.2、Collections.synchronizedList(new ArrayList<>());
         *     3.3、new CopyOnWriteArrayList<>();
         *
         * 4、优化建议(同样的错误不犯第2次)
         *     写时复制
         *   CopyOnWrite 容器即写时复制的容器。往一个容器添加元素的时候, 不直接往当前容器 Object[] 添加, 而是先将当前容器 Object[] 进行 Copy,
         *   复制出一个新的容器 Object[] newElements, 然后新的容器 Object[] newElements 里添加元素, 添加完元素之后,
         *   再将原容器的引用指向新的容器 setArray(newElements); 这样做的好处是可以对 CopyOnWrite 容器进行并发的读,
         *   而不需要加锁, 因为当前容器不会添加任何元素。所以 CopyOnWrite 容器也是一种读写分离的思想, 读和写不同的容器
         *   public boolean add(E e) {
         *           final ReentrantLock lock = this.lock;
         *           lock.lock();
         *           try {
         *               Object[] elements = getArray();
         *               int len = elements.length;
         *               Object[] newElements = Arrays.copyOf(elements, len + 1);
         *               newElements[len] = e;
         *               setArray(newElements);
         *               return true;
         *           } finally {
         *               lock.unlock();
         *           }
         *      }
         */
    }

}

CopyOnWriteArraySet

ConcurrentHashMap

发布了75 篇原创文章 · 获赞 77 · 访问量 4137

猜你喜欢

转载自blog.csdn.net/qq_35340189/article/details/104566490
今日推荐