CopyOnWrite容器及其思想

211 阅读2分钟

写时复制,简称COW,基本思想是读的时候多线程之间共享内容,当一条线程修改内容时,会进行copy资源进行修改形成新的内容,即读写分离的思想,读和写不同的容器。JUC中提供了CopyOnWriteArrayList和CopyOnWriteArraySet。

其好处在于对COW容器的并发读不需要加锁 CopyOnWriteArrayList的add方法,调用的时候是需要加锁的,否则多线程写的时候会copy出多个副本

/**  
 * Appends the specified element to the end of this list. * * @param e element to be appended to this list  
 * @return {@code true} (as specified by {@link Collection#add})  
 */public boolean add(E e) {  
    final ReentrantLock lock = this.lock;
    //lock操作放在try catch块外面,这样即使获取锁异常(比如自定义的时候)也不会无故释放锁
    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();  
    }  
}

//读就不需要加锁了
@SuppressWarnings("unchecked")  
private E get(Object[] a, int index) {  
    return (E) a[index];  
}

模仿COW思想实现COWMap

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;  
        }  
    }  
}

COW容器缺点

因为写时复制的机制,在进行写操作的时候会有两个对象在内存中(注意:在复制的时候只是复制容器里的引用,只是在写的时候会创建新对象添加到新容器里,而旧容器的对象还在使用,所以有两份对象内存),当对象的大小比较大的时候,很有可能造成频繁的GC 此外COW容器只能保证数据的最终一致性,不能保证实时一致性

PS: 并发容器之CopyOnWriteArrayList