美文网首页
java容器——CopyOnWriteArrayList/Set

java容器——CopyOnWriteArrayList/Set

作者: LiveMoment | 来源:发表于2018-08-15 10:44 被阅读11次

    夯实基础系列:
    基础是否扎实,决定你是否能走的更稳更远。


    Copy-On-Write

    Copy-On-Write(COW),写时复制,是一种程序优化策略:即所有人共享同一个对象,当某个线程修改时,需要将内容copy一份进行修改。修改后,所有线程访问修改后的对象。

    这是一种延时懒惰策略。从JDK1.5开始Java并发包里提供了两个使用CopyOnWrite机制实现的并发容器:CopyOnWriteArrayList和CopyOnWriteArraySet。

    当我们往一个容器添加元素的时候,不直接往当前容器添加,而是先将当前容器进行Copy,复制出一个新的容器,然后新的容器里添加元素,添加完元素之后,再将原容器的引用指向新的容器。这样做的好处是可以对CopyOnWrite容器进行并发的读,而不需要加锁,因为当前容器不会添加任何元素。所以CopyOnWrite容器也是一种读写分离的思想,读和写不同的容器。

    主要方法

    访问类方法——无锁访问

    访问类方法,主要包括get(), indexof(), contains(), empty(), size()等方法

       /**
         * The lock protecting all mutators.  (We have a mild preference
         * for builtin monitors over ReentrantLock when either will do.)
         */
        final transient Object lock = new Object();
    
        /** The array, accessed only via getArray/setArray. */
        // Android-changed: renamed array -> elements for backwards compatibility
        private transient volatile Object[] elements;
    
        final Object[] getArray() {
            return elements;
        }
    
        @SuppressWarnings("unchecked")
        private E get(Object[] a, int index) {
            return (E) a[index];
        }
    
        /**
         * @throws IndexOutOfBoundsException
         */
        public E get(int index) {
            return get(getArray(), index);
        }
    
        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;  //允许有null的
            } else {
                for (int i = index; i < fence; i++)
                    if (o.equals(elements[i]))
                        return i;
            }
            return -1;
        }
    


    (TODO,这里留个小坑,java对象相等的判断)

    修改类方法——加锁、复制

    修改类的方法包括:set(), add(), remove(), removeRange(), addIfAbsent()等方法。

    public E set(int index, E element) {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            Object[] elements = getArray(); // 加锁,获取原来的容器
            E oldValue = get(elements, index); // 要替换的老数据
            if (oldValue != element) {
                int len = elements.length; // 原来容器的长度
                Object[] newElements = Arrays.copyOf(elements, len); // 拷贝原容器
                newElements[index] = element;
                setArray(newElements);
            } 
            return oldValue;
        } finally {
            lock.unlock();  
           //这里加锁用到了lock,为什么不用Sychronized呢?当然为了优化性能了
        }
    }
    
    /**
     * Removes the element at the specified position in this list.
     * Shifts any subsequent elements to the left (subtracts one from their
     * indices).  Returns the element that was removed from the list.
     * @throws IndexOutOfBoundsException
     */
    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();
        }
    }
    

    存在的问题

    内存占用问题

    copy-on-write采用写时复制的策略,所以在写操作的时候,内存中会同时存在两个对象,当内存占用高的时候,会导致yong gc或full gc。原来对象占用内存200M,新写入100M。内存中的对象300M?500M?
    同时这也提醒在使用copy-on-write机制时,注意不应保存过大的对象。

    数据一致性问题

    copy-on-write只能保证数据的最终一致性,不能保证数据的实时一致性。

    CopyOnWrite的应用场景

    CopyOnWrite并发容器用于读多写少的并发场景,比如白名单黑名单之类。

    课后思考题:

    1、还记得对源容器加锁是怎么实现的吗?为什么不用Sychronized?

    参考:
    http://ifeve.com/java-copy-on-write/

    相关文章

      网友评论

          本文标题:java容器——CopyOnWriteArrayList/Set

          本文链接:https://www.haomeiwen.com/subject/kymibftx.html