CopyOnWrite

介绍

在juc(java.util.concurrent)包下有着这么两个类,CopyOnWriteArrayList 和 CopyOnWriteArraySet。直译过来就是在写操作的时候复制。这体现了读写分离的思想。

  1. 在写操作的线程,会将数组复制出来一份进行操作。而原本的数组不会做改变。
  2. 读线程则不会受到影响,但是可能读到的是一个过期的数据。

只能保证最终的一致性,不能保证实时的一致性。

CopyOnWriteArrayList

下面看下源码(添加的时候):

public boolean add(E e) {
	// 添加的时候,上锁
    final ReentrantLock lock = this.lock;
    lock.lock();
    try {
    	// 原本的数组
        Object[] elements = getArray();
        // 原本数组的长度
        int len = elements.length;
        // 调用native方法进行复制
        Object[] newElements = Arrays.copyOf(elements, len + 1);
        // 新的元素
        newElements[len] = e;
        // 替换数组
        setArray(newElements);
        // 成功
        return true;
    } finally {
    	// 解锁
        lock.unlock();
    }
}

CopyOnWriteArraySet

// 内部维护的是一个 CopyOnWriteArrayList
private final CopyOnWriteArrayList<E> al;
public boolean add(E e) {
	// 会判断去重
    return al.addIfAbsent(e);
}
public boolean addIfAbsent(E e) {
    Object[] snapshot = getArray();
    // 如果遇到相同的会返回大于等于0的下标
    return indexOf(e, snapshot, 0, snapshot.length) >= 0 ? false :
    // -1 则add
        addIfAbsent(e, snapshot);
}

private static int indexOf(Object o, Object[] elements,
                           int index, int fence) {
    if (o == null) {
        for (int i = index; i < fence; i++)
            if (elements[i] == null)
                return i;
    } else {
        for (int i = index; i < fence; i++)
            if (o.equals(elements[i]))
                return i;
    }
    return -1;
}

private boolean addIfAbsent(E e, Object[] snapshot) {
    final ReentrantLock lock = this.lock;
    lock.lock();
    try {
        Object[] current = getArray();
        int len = current.length;
        // 判断是否已经被设置过
        if (snapshot != current) {
            // 优化丢失竞争,怕与另一个add操作冲突,common取最小值
            int common = Math.min(snapshot.length, len);
            for (int i = 0; i < common; i++)
           		// 如果有一项不同,就放弃修改
                if (current[i] != snapshot[i] && eq(e, current[i]))
                    return false;
            if (indexOf(e, current, common, len) >= 0)
                    return false;
        }
        Object[] newElements = Arrays.copyOf(current, len + 1);
        newElements[len] = e;
        setArray(newElements);
        return true;
    } finally {
        lock.unlock();
    }
}

场景:

在读多,写少的情况下适用。

缺点:

  1. 无法保证实时一致性
  2. 每次添加都会进行复制,对性能的消耗有点大
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值