CopyOnWrite、CopyOnWriteArrayList

CopyOnWrite指在“写”的时候,不是直接“写”源数据,而是把数据拷贝一份进行修改,再通过悲观锁或者乐观锁的方式写回。

那为什么不直接修改,而是要拷贝一份修改呢?

答:这是为了在“读”的时候不加锁。

CopyOnWriteArrayList

和ArrayList一样,CopyOnWriteArrayList的核心数据结构也是一个数组,代码如下:

public class CopyOnWriteArrayList<E> implements List<E>, RandomAccess,
Cloneable, java.io.Serializable {
// ...
private volatile transient Object[] array;
}

下面是CopyOnArrayList的几个“读”方法:

final Object[] getArray() {
return array;
}
//
public E get(int index) {
return elementAt(getArray(), index);
}
public boolean isEmpty() {
return size() == 0;
}
public boolean contains(Object o) {
return indexOf(o) >= 0;
}
public int indexOf(Object o) {
Object[] es = getArray();
return indexOfRange(o, es, 0, es.length);
}
private static int indexOfRange(Object o, Object[] es, int from, int to)
{
if (o == null) {
for (int i = from; i < to; i++)
if (es[i] == null)
return i;
} else {
for (int i = from; i < to; i++)
if (o.equals(es[i]))
return i;
}
return -1;
}

既然这些“读”方法都没有加锁,那么是如何保证“线程安全”呢?答案在“写”方法里面。

public class CopyOnWriteArrayList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable {
// 锁对象
final transient Object lock = new Object();
public boolean add(E e) {
    synchronized (lock) { // 同步锁对象
    Object[] es = getArray();
    int len = es.length;
    es = Arrays.copyOf(es, len + 1); // CopyOnWrite,写的时候,先拷贝一 份之前的数组。
    es[len] = e;
    setArray(es);
    return true;
    }
}
public void add(int index, E element) {
    synchronized (lock) { // 同步锁对象
    Object[] es = getArray();
    int len = es.length;
    if (index > len || index < 0)
        throw new IndexOutOfBoundsException(outOfBounds(index, len));
        Object[] newElements;
        int numMoved = len - index;
        if (numMoved == 0)
        newElements = Arrays.copyOf(es, len + 1);
    else {
        newElements = new Object[len + 1];
        System.arraycopy(es, 0, newElements, 0, index); //
        CopyOnWrite,写的时候,先拷贝一份之前的数组。
        System.arraycopy(es, index, newElements, index + 1,
        numMoved);
}
    newElements[index] = element;
    setArray(newElements); // 把新数组赋值给老数组
        }
    }
}

其他“写”方法,例如remove和add类似。

 

CopyOnWriteArraySet

CopyOnWriteArraySet 就是用 Array 实现的一个 Set,保证所有元素都不重复。其内部是封装的一个CopyOnWriteArrayList。

public class CopyOnWriteArraySet<E> extends AbstractSet<E> implements
java.io.Serializable {
// 新封装的CopyOnWriteArrayList
    private final CopyOnWriteArrayList<E> al;
    public CopyOnWriteArraySet() {
    al = new CopyOnWriteArrayList<E>();
    }
    public boolean add(E e) {
    return al.addIfAbsent(e); // 不重复的加进去
    }
}

 

 

 

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值