CopyOnWriteArrayList和CopyOnWriteArraySet 原理总结

参考链接:
聊聊并发-Java中的Copy-On-Write容器
Java并发编程与技术内幕:CopyOnWriteArrayList、CopyOnWriteArraySet源码解析

前言:CopyOnWriteArrayList和CopyOnWriteArraySet 感觉非常简单,其中CopyOnWriteArraySet是基于CopyOnWriteArrayList实现的,只有add的方法稍微有些不同,因为CopyOnWriteArraySet是Set也就是不能有重复的元素,故在CopyOnWriteArraySet中用了addIfAbsent(e)这样的方法。

1.CopyOnWriteArrayList

顾名思义 就是复制一个数组,对复制后产生的新数组进行操作,而旧的数组不会有影响,所以旧的数组可以依旧就行读取(可以看出来,读的时候如果有新的数据正在写是无法实时的读取到的,有延时,得等新数据写完以后,然后才可以读到新的数据)

CopyOnWriteArrayList add (需要锁)

如果多个线程同时去写,多线程写的时候会Copy出N个副本出来,那么可能内存花销很大,所以用一个锁ReetrantLock锁住,一次只能一个线程去添加,这个线程是可重入的

public boolean add(T 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();

    }

}

final void setArray(Object[] a) {
    array = a;
}

CopyOnWriteArrayList get (需要锁)

get直接get即可,因为获取的旧的值所以没有影响。

2.CopyOnWriteArraySet

ADD

代码很简单,就是遍历去判断有没有,有的话直接返回false,没有的话就就赋值到新的数组,然后把新数组的引用返回即可。

public boolean add(E e) {
return al.addIfAbsent(e); //调用CopyOnWriteArrayList的addIfAbsent方法,如果数据重复返回false,不加入
}
//如果已存在就不放入
public boolean addIfAbsent(E e) {
   final ReentrantLock lock = this.lock;
   lock.lock();//取得锁
   try {
       Object[] elements = getArray();
       int len = elements.length;
       Object[] newElements = new Object[len + 1];
       for (int i = 0; i < len; ++i) { //一个一个元素取出来进行对比
       if (eq(e, elements[i]))
           return false; // 跳出,list中已存在此元素
       else
           newElements[i] = elements[i]; //一个一个拷贝到新数组
       }
       newElements[len] = e;
       setArray(newElements);//设置新数组
       return true;//加入成功
   } finally {
       lock.unlock();//释放锁
   }
   }

你可能感兴趣的:(java面试,Java)