JUC併發工具六-CopyOnWrite集合

顧名思義,採用寫時複製技術,讀的時候不加鎖,寫數據的時候先加鎖,把當前數據複製一份進行寫操作,寫完畢後替換當前的數據,然後釋放鎖。
這種集合適用於讀多寫少的場景。寫數據的時候比較佔空間,典型的拿控件換時間。
常用的集合有
CopyOnWriteArrayList
CopyOnWriteArraySet
1 CopyOnWriteArrayList
首先看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();
        }
    }

remove方法

    public E remove(int index) {
        final ReentrantLock lock = this.lock;
        // 加鎖
        lock.lock();
        try {
            // 刪除元素
            Object[] elements = getArray();
            int len = elements.length;
            E oldValue = get(elements, index);
            int numMoved = len - index - 1;
            if (numMoved == 0)
                setArray(Arrays.copyOf(elements, len - 1));
            else {
                Object[] newElements = new Object[len - 1];
                System.arraycopy(elements, 0, newElements, 0, index);
                System.arraycopy(elements, index + 1, newElements, index,
                                 numMoved);
                setArray(newElements);
            }
            return oldValue;
        } finally {
            // 釋放鎖
            lock.unlock();
        }
    }

get方法
get方法沒什麼特別注意的,根據下標取元素即可

2 CopyOnWriteArraySet
CopyOnWriteArraySet底層就是CopyOnWriteArrayList。有人會說不對啊,set是不能重複的,list是可以重複的。你忽悠我?
源碼走起
首先看一下構造函數,look

    private final CopyOnWriteArrayList<E> al;

    /**
     * Creates an empty set.
     */
    public CopyOnWriteArraySet() {
        al = new CopyOnWriteArrayList<E>();
    }

    可以看到CopyOnWriteArraySet初始化的時候就是初始化了一個CopyOnWriteArrayList

    來看一下它的add方法是怎麼實現的

    public boolean add(E e) {
        return al.addIfAbsent(e);
    }


    對,你沒有看錯,它的add方法實際上就是調用的CopyOnWriteArrayList.addIfAbsent方法,沒有的時候才添加。
    然後你在看CopyOnWriteArraySet的其他方法

    public boolean contains(Object o) {
        return al.contains(o);
    }

    public boolean containsAll(Collection<?> c) {
        return al.containsAll(c);
    }

    public boolean addAll(Collection<? extends E> c) {
        return al.addAllAbsent(c) > 0;
    }

    public boolean remove(Object o) {
        return al.remove(o);
    }

    調用的都是CopyOnWriteArrayList的原生方法。換句話說,如果你不用CopyOnWriteArrayList的add方法,添加元素的時候只用addIfAbsent,那它就是一個CopyOnWriteArraySet

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章