Redis写快照的时候,用到了Linux底层的copy-On-Write技术,可能有些人没听过或者听过但是没有深入了解下这个技术,通俗易用地讲,写入时复制技术就是不同进程访问同一资源的时候,只有在写操作,才会去复制一份新的数据,否则都是访问同一个资源。
copy-On-Write,写入时复制,这个技术,准确的说应该是一种思想,在很多系统设计上都会用到,今天我们来谈一谈Java语言中,JDK运用这种写入时复制的思想的数据结构/容器,copyOnWriteArrayList。copyOnWriteArrayList,是一个写入时复制的容器,它是如何工作的呢?简单来说,就是平时查询的时候,都不需要加锁,随便访问,只有在写入/删除的时候,才会从原来的数据复制一个副本出来,然后修改这个副本,最后把原数据替换成当前的副本。修改操作的同时,读操作不会被阻塞,而是继续读取旧的数据。这点要跟读写锁区分一下。
我们来看看Java中JDK的源码实现,其实也是非常的简单,在add操作的时候,先使用synchronized进行加锁,保证同时只有1个线程进行变更,在变更的时候,先拷贝出来一个副本,先操作这个副本,操作完成后,再把现有的数据替换成这个副本。
优点
对于一些读多写少的数据,这种做法的确很不错,例如配置、黑名单、物流地址等变化非常少的数据,这是一种无锁的实现。可以帮我们实现程序更高的并发。
缺点
这种实现只是保证数据的最终一致性,在添加到拷贝数据而还没进行替换的时候,读到的仍然是旧数据。如果对象比较大,频繁地进行替换会消耗内存,从而引发Java的GC问题,这个时候,我们应该考虑其他的容器,例如ConcurrentHashMap。