zoukankan      html  css  js  c++  java
  • CopyOnWriteArrayList学习

    CopyOnWrite容器即写时复制的容器。通俗的理解是当我们往一个容器添加元素的时候,不直接往当前容器添加,而是先将当前容器进行Copy,复制出一个新的容器,然后新的容器里添加元素,添加完元素之后,再将原容器的引用指向新的容器。这样做的好处是我们可以对CopyOnWrite容器进行并发的读,而不需要加锁,因为当前容器不会添加任何元素。所以CopyOnWrite容器也是一种读写分离的思想,读和写不同的容器。

    之前一直没用过CopyOnWriteArrayList,只知道给ArrayList,直到多线程编程才发现ArrayList是线程非安全的,后来就了解到了CopyOnWriteArrayList;

    使用ArrayList出现的问题

    ArrayList<String> list=new ArrayList<String>();
    //        CopyOnWriteArrayList list=
            list.add("a");
            list.add("b");
            list.add("c");
    //        final ArrayList<String> testlist=new ArrayList<>(list);出错,ConcurrentModificationException错误
            final CopyOnWriteArrayList<String> testlist=new CopyOnWriteArrayList<>(list);
            Thread thread = new Thread(new Runnable() {
    
                int count = -1;
    
                @Override
                public void run() {
    
                    while(true){
    
                        testlist.add(count++ + "");
                    }
                }
            });
            thread.setDaemon(true); //在启动了线程之后随着main方法执行完毕而终止,否则一直停在while循环
            thread.start();
            Thread.currentThread().sleep(3);
            for(String s: testlist){
    
                System.out.println(s);
                System.out.println(testlist.hashCode());
            }

    换成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();
            }
        }
    final void setArray(Object[] a) {
            array = a;
        }

    add方法中,使用了锁,然后就数组copy一份,将原来的数组引用指向新的数组

    有优点就有缺点,缺点大概有这几方面

    1.内存占用问题,因为要进行数组的复制,这样就多了一份拷贝在内存中,如果数据比较大的话,比如100M,复制就会成为200M,这样有可能会造成频繁的yongGC和fullGC;

    2.实时一致性,CopyOnWrite容器只能保证数据的最终一致性,不能保证数据的实时一致性。所以如果你希望写入的的数据,马上能读到,请不要使用CopyOnWrite容器。

    根据CopyOnWrite的实现机制,可以去实现CopyOnWriteMap,CopyOnWriteSet等等;这类主要应用场景为多读少写的并发情况,比如我们针对网站设置一个IP过滤器,每个IP进来的时候先查询是否在过滤器里面,如果存在就阻断访问,然后每天再将当天访问超过10000次的IP加入到过滤器里面。

  • 相关阅读:
    Printing a DataGridView on DotNet Framework
    对比.NET PetShop和Duwamish来探讨Ado.NET的数据库编程模式
    PetShop配置readme
    关于DGVPrinter.cs中的PrintRange
    foobar2000 0.9.5正式版放出
    Another DataGridView Printer
    getline及读文件总结
    C++中文件的读取操作,如何读取多行数据,如何一个一个的读取数据
    vector的clear和swap
    写程序前不需指定数组中的常量,而是动态编译中决定
  • 原文地址:https://www.cnblogs.com/dpains/p/7133622.html
Copyright © 2011-2022 走看看