1. CopyOnWriteArrayList

CopyOnWriteArraySet 是它的马甲 底层实现采用了 写入时拷贝 的思想,增删改操作会将底层数组拷贝一份,更改操作在新数组上执行,这时不影响其它线程的并发读读写分离。 以新增为例:

  1. public boolean add(E e) {
  2. synchronized (lock) {
  3. // 获取旧的数组
  4. Object[] es = getArray();
  5. int len = es.length;
  6. // 拷贝新的数组(这里是比较耗时的操作,但不影响其它读线程)
  7. es = Arrays.copyOf(es, len + 1);
  8. // 添加新元素
  9. es[len] = e;
  10. // 替换旧的数组
  11. setArray(es);
  12. return true;
  13. }
  14. }

这里的源码版本是 Java 11,在 Java 1.8 中使用的是可重入锁而不是 synchronized

其它读操作并未加锁,例如:

  1. public void forEach(Consumer<? super E> action) {
  2. Objects.requireNonNull(action);
  3. for (Object x : getArray()) {
  4. @SuppressWarnings("unchecked") E e = (E) x;
  5. action.accept(e);
  6. }
  7. }

适合『读多写少』的应用场景

get 弱一致性

image.png

迭代器弱一致性

  1. CopyOnWriteArrayList<Integer> list = new CopyOnWriteArrayList<>();
  2. list.add(1);
  3. list.add(2);
  4. list.add(3);
  5. Iterator<Integer> iter = list.iterator();
  6. new Thread(() -> {
  7. list.remove(0);
  8. System.out.println(list);
  9. }).start();
  10. sleep1s();
  11. while (iter.hasNext()) {
  12. System.out.println(iter.next());
  13. }

不要觉得弱一致性就不好

  • 数据库的 MVCC 都是弱一致性的表现
  • 并发高和一致性是矛盾的,需要权衡