JAVA并发容器-写时复制容器
2019-07-31 本文已影响17人
xiaolyuh
写时复制的容器。通俗的理解是当我们往一个容器添加元素的时候,不直接往当前容器添加,而是先将当前容器进行Copy,复制出一个新的容器,然后新的容器里添加元素,添加完元素之后,再将原容器的引用指向新的容器。
这样做的好处是我们可以对容器进行并发的读,而不需要加锁,因为当前容器不会添加任何元素。所以写时复制容器也是一种读写分离的思想,读和写不同的容器。如果读的时候有多个线程正在向容器添加数据,读还是会读到旧的数据,因为写的时候不会锁住旧的,只能保证最终一致性。
适用读多写少的并发场景,常见应用:白名单/黑名单, 商品类目的访问和更新场景。
CopyOnWriteArrayList和CopyOnWriteArraySet就是写时复制容器。
CopyOnWriteArrayList 类图

底层依然是数组,基于ReentrantLock来做并发控制。
add()
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;
// 替换数组
setArray(newElements);
return true;
} finally {
lock.unlock();
}
}
CopyOnWriteArraySet类图

CopyOnWriteArraySet就是基于CopyOnWriteArrayList来实现的。
测试方法
@Test
public void testCopyOnWrite() {
CopyOnWriteArrayList<Integer> copyOnWriteArrayList = new CopyOnWriteArrayList<>();
copyOnWriteArrayList.add(5);
copyOnWriteArrayList.add(3);
copyOnWriteArrayList.add(4);
copyOnWriteArrayList.add(2);
copyOnWriteArrayList.add(3);
System.out.println(copyOnWriteArrayList);
CopyOnWriteArraySet<Integer> copyOnWriteArraySet = new CopyOnWriteArraySet<>();
copyOnWriteArraySet.add(5);
copyOnWriteArraySet.add(3);
copyOnWriteArraySet.add(4);
copyOnWriteArraySet.add(2);
copyOnWriteArraySet.add(3);
System.out.println(copyOnWriteArraySet);
}
输出:
[5, 3, 4, 2, 3]
[5, 3, 4, 2]
源码
https://github.com/wyh-spring-ecosystem-student/spring-boot-student/tree/releases
spring-boot-student-concurrent 工程
layering-cache
为监控而生的多级缓存框架 layering-cache这是我开源的一个多级缓存框架的实现,如果有兴趣可以看一下