高并发容器--CopyOnWrite

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/yeyincai/article/details/52774769

—–CopyOnWrite容器即写时复制的容器。通俗的讲就是往容器里面写数据的时候,不再当前容器写数据,而是将当前的容器拷贝一份,往拷贝新的容器里面写数据,添加完元素后,再将原容器指向新的容器。这样做的好处就是,并发读的时候不需要加锁,因为当前容器没有添加任何元素,不过写的时候需要加锁,所以CopyOnWrite也是一种读写分离的思想,适用于读多写少的并发场景,CopyOnWriteArrayList采用“写入时复制”策略,对容器的写操作将导致的容器中基本数组的复制,性能开销较大。所以在有写操作的情况下,CopyOnWriteArrayList性能不佳,而且如果容器容量较大的话容易造成溢出。
public class Test1 {

final static CopyOnWriteArrayList copyOnWriteArrayList = new CopyOnWriteArrayList();
final static AtomicInteger atomicInteger = new AtomicInteger(3);

public static void main(String[] args) {
    List<String> lists = Lists.newArrayList();
    lists.add("1");
    lists.add("2");
    //整体加入会更好,单个加入需要消耗大量性能
    copyOnWriteArrayList.addAll(lists);

    product();
    comsumer();

    try {
        TimeUnit.MINUTES.sleep(1);
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
}

static void product() {
    for (int i = 0; i < 5; i++) {
        new Thread(() -> {
            try {
                TimeUnit.NANOSECONDS.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            copyOnWriteArrayList.add(atomicInteger.incrementAndGet()+"");
        }).start();
    }
}

static void comsumer() {
    //读多写少
    for (int i = 0; i < 10000; i++) {
        new Thread(() -> {
                System.out.println(copyOnWriteArrayList.toString());
        }).start();
    }

}

}

CopyOnWrite的缺点

内存占用的问题:CopyOnWrite写的复制机制,导致在写的时候内存存在两份对象(注意:在复制的时候只是复制容器对象的引用,只是在写的时候会在创建一个新对象添加到新的容器里,而旧的容器还在使用)。如果这些对象比较大,那么这个时候很可能造成频繁Yong GC和Full GC,针对这种大对象内存占用问题,可以通过压缩容器的元素来减少大对象的内存消耗,比如10进制变成36进制。或者不使用CopyOnWrite,而使用其它并发容器,ConcurrentHashMap。

数据一致性问题:由于采用了读写分离的思想,所以读和写可能获取的数据是不一样的,它只能保证数据的最终一致性,不能保证数据的实时一致性。

猜你喜欢

转载自blog.csdn.net/yeyincai/article/details/52774769