JAva同時の集合クラスの不安全問題の深い分析


一、List

 public static void listNotSafe(){
        List list = new ArrayList<>(); //new ArrayList<>();  new 

        List list1 = Collections.synchronizedList(new ArrayList<>());
        CopyOnWriteArrayList objects = new CopyOnWriteArrayList<>();

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

        }
        //java.util.ConcurrentModificationException
    }

2.故障現象java.util.ConcurrentModificationException 3.原因を引き起こす


1つのスレッドが書かれていて、もう1つのスレッドが奪い取りに来て、データが一致しない、すなわち同時修正による異常4.ソリューション

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

  • 読み書きが少ないときはCopeOnWriteArrayListというクラスがおすすめです
    書き込み時にコピーし、読み書きを分離するメリット:読み取り操作が完全にロックされていない
    使用シーン:書き込み操作が非常に少ない場合、読み書きの短い不一致を許容できます.
    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 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();}  

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

  •