1、ArraryList相关

ArrayList是线程不安全的,在多线程下同时操作一个集合会出java.util.ConcurrentModificationException异常(并发修改异常),如下所示:

    public static void main(String[] args) throws IOException {
        List<String> list = new ArrayList<>();
        for (int i = 0; i < 30; i++) {
            new Thread(() -> {
                list.add(UUID.randomUUID().toString().substring(0, 8));
                System.out.println(list);
            }, "thread" + i).start();
        }
    }

  解决办法:① 、使用List<String> list = new Vector<>();

       ②、 使用List<String> list = Collections.synchronizedList(new ArrayList<>());

       ③、 使用List<String> list = new CopyOnWriteArrayList<>();

Vector线程安全原因:

    /**
     * Appends the specified element to the end of this Vector.
     *
     * @param e element to be appended to this Vector
     * @return {@code true} (as specified by {@link Collection#add})
     * @since 1.2
     */
    public synchronized boolean add(E e) {
        modCount++;
        ensureCapacityHelper(elementCount + 1);
        elementData[elementCount++] = e;
        return true;
    }

CopyOnWriteArrayList线程安全原因:

/**
     * Appends the specified element to the end of this list.
     *
     * @param e element to be appended to this list
     * @return {@code true} (as specified by {@link Collection#add})
     */
    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();
        }
    }

ReentrantLock和synchronized 区别:https://baijiahao.baidu.com/s?id=1648624077736116382&wfr=spider&for=pc

 ArrayList生僻知识点:

①、创建时可以自己指定长度,不指定默认长度为10,每次扩容以当前长度0.5倍进行扩容,第一次10,第二次15

②、ArrayList底层是数组结构,所以不能通过forEache和增强for循环去进行删除(迭代器方式)和新增

③、可以通过正常for循环去操作for(int i=0;i<list.size();i++),虽然此方法不报错,但是不推荐(涉及到数组下标移动问题)

④、可通过临时集合将待删除数据记录,待循环结束后,使用removeAll()一起删除

提示:Vectore初始默认长度也为10,但是每次扩容都是按1倍进行扩容,第一次10,第二次20

2、HashSet相关

 HashSet为线程不安全的,在多线程下同时操作一个集合也会出java.util.ConcurrentModificationException异常(并发修改异常),实例如下:

    public static void main(String[] args) throws IOException {
        Set<String> list = new HashSet<>();
        for (int i = 0; i < 30; i++) {
            new Thread(() -> {
                list.add(UUID.randomUUID().toString().substring(0, 8));
                System.out.println(list);
            }, "thread" + i).start();
        }
    }

 

解决办法:

①、使用Set<String> list = Collections.synchronizedSet(new HashSet<>());

②、使用Set<String> list = new CopyOnWriteArraySet<>();

CopyOnWriteArraySet的底层依旧是采用和CopyOnWriteArrayList,如下所示:

     /**
     * Creates an empty set
     */
    public CopyOnWriteArraySet() {
        al = new CopyOnWriteArrayList<E>();
    }

 

HashSet生僻知识点:

①、HashSet底层是通过HashMap进行实现的,故此HashMap也会有线程安全问题

②、HashSet的add方法底层就是调用的HashMap的put方法,只不过value全部都是一个常量对象private static final Object PRESENT = new Object();

③、HashSet的元素全部都是作为HashMap的key值,所以自定义HashSet元素相等方法时必须要重写HashCode方法

3、HashMap相关

HashMap跟HashSet一样,因为HashSet底层就是采用HashMap,所以也会有线程安全的问题

解决办法:

①、使用Map<String, Object> objectObjectMap = Collections.synchronizedMap(new HashMap<>());

②、使用Map<Object, Object> objectObjectConcurrentHashMap = new ConcurrentHashMap<>();

③、使用Map<Object, Object> hashtable = new Hashtable<>();

Hashtable和Vector相似,都是jdk1.0的产物,都是采用了synchronized关键字进行枷锁,所以都是线程安全,但是效率稍微低一点

ConcurrentHashMap则是采用对链表进行分段加锁实现现在安全,效率比HashTable高很多,推荐使用

HashMap生僻知识点:

①、HashMap底层是数组+链表结构实现

②、创建一个HashMap是默认数组长度为16(必须是2的幂),每次扩容时以之前的2倍进行扩容,第一次16,第二次48

③、HashMap的初始容量可以自己指定,一版要求都是以2的n次幂的形式存在的

结论:

HashMap计算添加元素的位置时,使用的位运算,这是特别高效的运算;另外,HashMap的初始容量是2的n次幂,扩容也是2倍的形式进行扩容,是因为容量是2的n次幂,可以使得添加的元素均匀分布在HashMap中的数组上,减少hash碰撞,避免形成链表的结构,使得查询效率降低!

为什么HashMap的容量是2的n次幂?

 HashMap的容量为什么是2的n次幂,和这个(n - 1) & hash的计算方法有着千丝万缕的关系,符号&是按位与的计算,这是位运算,计算机能直接运算,特别高效,按位与&的计算方法是,只有当对应位置的数据都为1时,运算结果也为1,当HashMap的容量是2的n次幂时,(n-1)的2进制也就是1111111***111这样形式的,这样与添加元素的hash值进行位运算时,能够充分的散列,使得添加的元素均匀分布在HashMap的每个位置上,减少hash碰撞

posted on 2020-08-03 16:14  蓝色恋人  阅读(590)  评论(0编辑  收藏  举报