码迷,mamicode.com
首页 > 编程语言 > 详细

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

时间:2019-08-16 00:20:41      阅读:112      评论:0      收藏:0      [点我收藏+]

标签:方案   cti   集合   cto   present   ring   init   length   rand   

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

 

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

标签:方案   cti   集合   cto   present   ring   init   length   rand   

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

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!