zoukankan      html  css  js  c++  java
  • 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<>();

  • 相关阅读:
    VS2005使用AjaxPro.2
    一步步教你实现富文本编辑器(第三部分)
    Ajax实现在textbox中输入内容,动态从数据库中模糊查询显示到下拉框中
    一步步教你实现跨游览器的JS日历
    2009年中国10大网络公司业绩比较
    Beautiful smile and love
    NGINX 配置404错误页面转向
    wget使用范例
    mcrypt以及mhash扩展的安装!
    linux下常用压缩格式的压缩与解压方法
  • 原文地址:https://www.cnblogs.com/wjh123/p/11259409.html
Copyright © 2011-2022 走看看