java面试-集合类不安全问题及解决方案

一、List

1、代码演示

public class ArrayListNotSafeDemo {

    public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        for (int i = 1; i <= 30; i++) {
            new Thread(() -> {
                //Constructs an empty list with an initial capacity of ten.
                list.add(UUID.randomUUID().toString().substring(0, 8));
                System.out.println(list);
            }, String.valueOf(i)).start();
        }
    }
}

2、故障现象

java.util.ConcurrentModificationException

3、导致原因

一个线程正在写,另一线程过来抢夺,导致数据不一致,即并发修改导致的异常

4、解决方案

  • new Vector<>()
  • Collections.synchronizedList()
  • new CopyOnWriteArrayList<>()   

         在读多写少的时候推荐使用 CopeOnWriteArrayList 这个类

         写时复制,读写分离的思想 好处:读操作完全无锁

         使用场景 :写操作非常少的场合,能容忍读写的短暂不一致。

                        CopyOnWriteArrayList迭代器是只读的,不支持增删改。

5、 CopyOnWriteArrayList源码解读:

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

二、Set

1、代码演示:

public class HashSetNotSafeDemo {

    public static void main(String[] args) {
        Set<String> list = new HashSet<>();
        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();
        }
    }
}

2、解决方案:

  • Collections.synchronizedSet()
  • new CopyOnWriteArraySet<>()   

3、CopyOnWriteArraySet底层源码:

底层使用CopyOnWriteArrayList

    public CopyOnWriteArraySet() {
        al = new CopyOnWriteArrayList<E>();
    }  

4、HashSet底层源码

HashSet的key是你add()的值,value是一个叫PRESENT Object类型的常量,即HashSet只关心key

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

   
    private static final Object PRESENT = new Object();

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

三、Map  

1、代码演示:

public class HashMapNotSafeDemo {

    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, 8));
                System.out.println(map);
            }, String.valueOf(i)).start();
        }
    }
}

2、解决方案

  • Collections.synchronizedMap()
  • new ConcurrentHashMap<>();

原文地址:https://www.cnblogs.com/wjh123/p/11259409.html