zoukankan      html  css  js  c++  java
  • java基础之ArrayList 和Vector、CopyOnWriteArrayList

    1.我们都知道ArrayList 是线程不安全的,不存在同步。

    2.像Vector这种,add、remove方法都是原子操作,不会被打断,但也仅限于此,如果有个线程在遍历某个Vector、有个线程同时在add这个Vector,99%的情况下都会出现ConcurrentModificationException,也就是fail-fast机制

    3.说到底CopyOnWriteArrayList 是最安全的,CopyOnWriteArrayList为什么能解决同步的问题呢?CopyOnWrite容器即写时复制的容器。通俗的理解是当我们往一个容器添加元素的时候,不直接往当前容器添加,而是先将当前容器进行Copy,复制出一个新的容器,然后新的容器里添加元素,添加完元素之后,再将原容器的引用指向新的容器。CopyOnWriteArrayList中add/remove等写方法是需要加锁的,目的是为了避免Copy出N个副本出来,导致并发写。但是。CopyOnWriteArrayList中的读方法是没有加锁的。

    fail-fast机制 是在迭代的时候产生的,当多个线程同时对Arraylist 进行add时,就会引发fail-fast机制。

     从上面的源代码我们可以看出,迭代器在调用next()、remove()方法时都是调用checkForComodification()方法,它检测modCount == expectedModCount ? 若不等则抛出ConcurrentModificationException 异常,从而产生fail-fast机制。到了这一步我们也知道了,想要弄清楚fail-fast机制,首先我们需要搞清楚modCount 和expectedModCount。

    expectedModCount 是在IteratorTest中定义的:int expectedModCount = ArrayList.this.modCount;所以他的值是不可能会修改的,所以会变的就是modCount。modCount是在 AbstractList 中定义的,为全局变量:

    protected transient int modCount = 0;

    那么他什么时候因为什么原因而发生改变呢?请看ArrayList的源码:

     从上面的源代码我们可以看出,只要是涉及了改变ArrayList元素的个数的方法都会导致modCount的改变。所以我们这里可以初步判断由于expectedModCount 与modCount的改变不同步,导致两者之间不等,从而产生fail-fast机制。

    我想各位已经基本了解了fail-fast的机制,那么平常我们如何去规避这种情况呢?这里有两种解决方案:

    方案一:在遍历过程中所有涉及到改变modCount值得地方全部加上synchronized或者直接使用Collections.synchronizedList(不推荐)

    方案二:使用CopyOnWriteArrayList来替换ArrayList。

    转自  :https://baijiahao.baidu.com/s?id=1638201147057831295&wfr=spider&for=pc

  • 相关阅读:
    ZooKeeper基本原理
    ElasticSearch的基本原理与用法
    Solr与MySQL查询性能对比
    MySQL性能优化总结
    Java并发集合及线程池实现原理
    Java垃圾回收机制
    Java Spring的IoC和AOP的知识点速记
    基于Solr的空间搜索
    系统学习消息队列分享(十) 如何实现高性能的异步网络传输?
    系统学习消息队列分享(九) 如何使用异步设计提升系统性能?
  • 原文地址:https://www.cnblogs.com/ScarecrowAnBird/p/13056301.html
Copyright © 2011-2022 走看看