CopyOnWrite解析

核心思想

读写分离,空间换时间,避免为保证并发安全导致的激烈的锁竞争。

关键点

1、CopyOnWrite适用于读多写少的情况,最大程度的提高读的效率;
2、CopyOnWrite是最终一致性,在写的过程中,原有的读的数据是不会发生更新的,只有新的读才能读到最新数据;
3、如何使其他线程能够及时读到新的数据,需要使用volatile变量;
4、写的时候不能并发写,需要对写操作进行加锁;

源码解析

CopyOnWriteArrayList 相对于 ArrayList 线程安全,底层通过复制数组的方式来实现,其核心概念就是: 数据读取时直接读取,不需要锁,数据写入时,需要锁,且对副本进行操作。那么当数据的操作以读取为主时,我们便可以省去大量的读锁带来的消耗。同时为了能让多线程操作List时,一个线程的修改能被另一个线程立马发现,CopyOnWriteList采用了Volatile关键词来进行修饰,即每次数据读取不从缓存里面读取,而是直接从数据的内存地址中读取。
以CopyOnWriteArrayList 的add()操作为例来看

  // 这个数组是核心的,因为用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();
      }
  }

结论

总结而言,多线程实现COW实际上就是以空间换取时间使得数据读取时不需要锁。只是减少了读锁的开销,但与常规的多线程操作共享数据的本质没有什么区别。

参考

https://zhuanlan.zhihu.com/p/114547256
https://cloud.tencent.com/developer/article/1821632
https://blog.csdn.net/javageektech/article/details/108114252

上一篇:HashMap&ConcurrentHashMap


下一篇:java并发:CopyOnWrite机制