Java并发包学习笔记 CopyOnWriteArrayList

  1. Copy-On-Write

Copy-On-Write是一种程序设计中的优化策略,基本思路是,从一开始,大家都共享同一个内容,当某个人想要修改这个内容的时候,才会正在把内容copy出去,形成一个新的内容,然后再改,这是一种延迟懒惰策略。

  1. CopyOnWrite容器

CopyOnWrite是写时进行复制的容器。通俗理解是当我们往一个容器添加元素的时候,不直接往当前容器添加,而是先将当前容器复制到一个新的容器,然后再往新的容器中添元素,再将原容器的引用指向新的容器。

这样做的好处是,可以对CopyOnWrite容器进行并发的读,而不需要加锁。
所以CopyOnWrite容器是一种读写分离的思想,读和写不同的容器。

  1. CopyOnWriteArrayList 的实现原理

1)add方法:在添加新元素的时候,是需要加锁的。否则多线程同时写会copy出N个副本。

public boolean add(T 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;
}

读的时候不需要加锁,如果读的时候有多个线程正在想ArrayList中添加元素,读还会读到旧的数据,因为写的时候不会锁住旧的ArrayList.
读的代码:
public E get(int index) {
return get(getArray(), index);
}

综上,CopyOnWriteArrayList, 不允许多线程一起写,一起写时要排队;但允许写的时候多线程一起读,因为写完后直接指针切换。

了解了Copy-On-Write机制,可以自己实现各种Copy-On-Write容器,如实现个CopyOnWriteMap:

import java.util.Collection;
import java.util.Map;
import java.util.Set;

public class CopyOnWriteMap<K, V> implements Map<K, V>, Cloneable {
private volatile Map<K, V> internalMap;

public CopyOnWriteMap() {
    internalMap = new HashMap<K, V>();
}

public V put(K key, V value) {

    synchronized (this) {
        Map<K, V> newMap = new HashMap<K, V>(internalMap);
        V val = newMap.put(key, value);
        internalMap = newMap;
        return val;
    }
}

public V get(Object key) {
    return internalMap.get(key);
}

public void putAll(Map<? extends K, ? extends V> newData) {
    synchronized (this) {
        Map<K, V> newMap = new HashMap<K, V>(internalMap);
        newMap.putAll(newData);
        internalMap = newMap;
    }
}

}

  1. CopyOnWrite的应用场景

CopyOnWrite并发容器用于读多写少的并发场景。

  1. CopyOnWrite的缺点

1)费内存;
2)数据一致性。

1)内存占用问题:CopyOnWrite写时采用复制机制,所以在写时,内存中会同时有2个对象的内存,即旧的对象和新写入的对象。可能会造成频繁Full GC.

2)数据一致性问题。CopyOnWrite容器只能保证数据的最终一致性,不能保证数据的实时一致性。所以如果你希望写入的数据能够马上独到,不用使用CopyOnWrite容器。

猜你喜欢

转载自blog.csdn.net/shijinghan1126/article/details/86500663