zoukankan      html  css  js  c++  java
  • java并发容器CopyOnWriteArrayList 使用场景和内部实现分析

    java并发容器CopyOnWriteArrayList
    CopyOnWriteArrayList
    顾名思义,当数组有变化时重新建立一个新的数组

    其设计是对于线程安全容器Vector使用中出现问题的一种解.
    在Vector容器中,当需要执行复合操作
    例如:
    //代码1

    class Observable 
    {
    private List<Observer> observers=new Vector<Observer>();
    
    public void addObserver(){...}
    public void removeObserver(){...}
    public void notify()
    {
    Iterator<Observer> itr=observers.iterator();
    while(itr.hasNext()){
    Observer observer=itr.next();
    observer.notify();
    }
    return;
    }
    }

    Observable中的notify方法在单线程中的实现是正常的,但在多线程中,由于在notify执行过程中observers数组的内容可能会发生改变,导致遍历失效.即使observers本身是线程安全的也于是无补

    通常解决这个问题,可以使用同步方法或者加锁
    //代码2

    class Observable 
    {
    private List<Observer> observers=new Vector<Observer>();
    
    public synchronized void addObserver(){...}
    
    public synchronized void removeObserver(){...}
    
    //同步方法
    public synchronized void notify()
    {
    Iterator<Observer> itr=observers.iterator();
    while(itr.hasNext()){
    Observer observer=itr.next();
    observer.notify();
    }
    return;
    }
    }
    

      

    这样的解决方案中notify的同步导致另外一个问题,即活跃性问题.当observers中有很多元素或者每一个元素的notify方法调用需要很久时,此方法将长时间持有锁.导致其他任何想修改observers的行为阻塞.最后严重影响程序性能

    CopyOnWriteArrayList即在这种场景下使用.一个需要在多线程中操作,并且频繁遍历.
    其解决了由于长时间锁定整个数组导致的性能问题.
    其解决方案即写时拷贝。

    我们先来贴出使用CopyOnWriteArrayList的Observable代码
    //代码3

    class Observable 
    {
    private List<Observer> observers=new CopyOnWriteArrayList<Observer>();
    
    public void addObserver(){...}
    
    public void removeObserver(){...}
    
    public void notify()
    {
    Iterator<Observer> itr=observers.iterator();
    while(itr.hasNext()){
    Observer observer=itr.next();
    observer.notify();
    }
    return;
    }
    }

    Observable的notify方法和代码1相同.但其不会有多线程同时操作的问题.其中的奥秘,通过分析源码可知
    当CopyOnWriteArrayList添加或者删除元素时,其实现为根据当前数组重新建立一个新数组..

    Iterator<Observer> itr=observers.iterator();


    当我们获取CopyOnWriteArrayList的迭代器时,迭代器内保存当前数组的引用.之后如果别的线程改变CopyOnWriteArrayList中元素,则根据CopyOnWriteArrayList的特性,其实并没有改变这个迭代器指向数组的内容.

    如图



  • 相关阅读:
    ThinkPHP 3.2.3
    MobaXterm 可替代 XShell4 和 Xftp4
    SourceTree 合并DEV分支到master
    WOX 和 everything 差不多,挺不错也
    function 的入参 如果是指针的话,如果你用的好的话,会颠覆三观啊 这里就是指对象,数组不用考虑 // 夏娃的苹果
    buildFast.js node.js 快速发布到gitee上,这样就不用每次点击,并且自动弹出发布页面,再点击发布,完美!
    velocity.js
    【linux之sed及vim】
    linux curl命令详解
    哈夫曼(huffman)树和哈夫曼编码
  • 原文地址:https://www.cnblogs.com/duchanggang/p/4627082.html
Copyright © 2011-2022 走看看