CopyOnWrite

1. 读多写少的场景引发的问题?

  读写互斥,在写的过程中,大量的读操作阻塞,无法执行。

2. CopyOnWrite的思想来解决(参考JDK里的 CopyOnWriteArrayList 的源码)

  原数据用于读操作,原数据的拷贝副本用于写操作,副本写完马上赋值给原数据,使用volatile关键字。

// 这个数组是核心的,因为用volatile修饰了
// 只要把最新的数组对他赋值,其他线程立马可以看到最新的数组
private transient volatile Object[] array;

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;
        // 然后把副本数组赋值给volatile修饰的变量
        setArray(newElements);
        return true;
    } finally {
        lock.unlock();
    }
}
final void setArray(Object[] a) {
    array = a;
}

 

3. 在kafka中的应用,内存缓冲用到的数据结构

private final ConcurrentMap<TopicPartition, Deque<RecordBatch>> batches = new CopyOnWriteMap<TopicPartition, Deque<RecordBatch>>();
 // 典型的volatile修饰普通Map
    private volatile Map<K, V> map;
    @Override
    public synchronized V put(K k, V v) {
        // 更新的时候先创建副本,更新副本,然后对volatile变量赋值写回去
        Map<K, V> copy = new HashMap<K, V>(this.map);
        V prev = copy.put(k, v);
        this.map = Collections.unmodifiableMap(copy);
        return prev;
    }
    @Override
    public V get(Object k) {
        // 读取的时候直接读volatile变量引用的map数据结构,无需锁
        return map.get(k);
    }

 

转载出处
作者:石杉的架构笔记
链接:https://juejin.im/post/5cd1724cf265da03a7440aae
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

 

posted @ 2019-06-12 14:51  华格瑞沙  阅读(234)  评论(0编辑  收藏  举报