JAVA8之CopyOnWriteArrayList

类继承层次

在这里插入图片描述

底层数据结构

同ArrayList

默认初始容量

0

最大容量

等于java数组最大长度

扩容算法

每次新建一个原数组长度加1的数组然后将原数组拷贝到新数组,最后把新增元素加进新数组

            Object[] elements = getArray();
            int len = elements.length;
            Object[] newElements = Arrays.copyOf(elements, len + 1);
            newElements[len] = e;
            setArray(newElements);

主要操作时间复杂度

同ArrayList

安全性

线程安全

线程安全实现原理

每个CopyOnWriteArrayList对象持有一个ReentrantLock,在每个写操作上加锁,以add方法为例:

    /**
     * Appends the specified element to the end of this list.
     *
     * @param e element to be appended to this list
     * @return {@code true} (as specified by {@link Collection#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();
        }
    }

问题

CopyOnWriteArrayList的弱一致性

写操作加锁隔离,但是读操作使用快照读,无法保证按时序的一致性。这也是iterator接口为什么屏蔽了写操作的原因:

        /**
         * Not supported. Always throws UnsupportedOperationException.
         * @throws UnsupportedOperationException always; {@code remove}
         *         is not supported by this iterator.
         */
        public void remove() {
            throw new UnsupportedOperationException();
        }

        /**
         * Not supported. Always throws UnsupportedOperationException.
         * @throws UnsupportedOperationException always; {@code set}
         *         is not supported by this iterator.
         */
        public void set(E e) {
            throw new UnsupportedOperationException();
        }

        /**
         * Not supported. Always throws UnsupportedOperationException.
         * @throws UnsupportedOperationException always; {@code add}
         *         is not supported by this iterator.
         */
        public void add(E e) {
            throw new UnsupportedOperationException();
        }

可疑的静态代码块

CopyOnWriteArrayList中有这么一段静态代码块:

    static {
        try {
            UNSAFE = sun.misc.Unsafe.getUnsafe();
            Class<?> k = CopyOnWriteArrayList.class;
            lockOffset = UNSAFE.objectFieldOffset
                (k.getDeclaredField("lock"));
        } catch (Exception e) {
            throw new Error(e);
        }
    }

在看下lock和lockOffset属性的声明以及resetLock方法

    final transient ReentrantLock lock = new ReentrantLock();
    private static final long lockOffset;
   // Support for resetting lock while deserializing
   private void resetLock() {
       UNSAFE.putObjectVolatile(this, lockOffset, new ReentrantLock());
   }

在来看下一段反序列化代码

   /**
    * Reconstitutes this list from a stream (that is, deserializes it).
    * @param s the stream
    * @throws ClassNotFoundException if the class of a serialized object
    *         could not be found
    * @throws java.io.IOException if an I/O error occurs
    */
   private void readObject(java.io.ObjectInputStream s)
       throws java.io.IOException, ClassNotFoundException {

       s.defaultReadObject();

       // bind to new lock
       resetLock();

       // Read in array length and allocate array
       int len = s.readInt();
       SharedSecrets.getJavaOISAccess().checkArray(s, Object[].class, len);
       Object[] elements = new Object[len];

       // Read in all elements in the proper order.
       for (int i = 0; i < len; i++)
           elements[i] = s.readObject();
       setArray(elements);
   }

到这里你大概就能猜到了。因为lock对象是一个transient修饰到对象,不会被序列化,所以反序列化的时候需要重新创建这个对象且放到指定到位置上。那可不可以把lock对象前面的transient去掉,这样不就可以了序列化以及反序列化整个CopyOnWriteArrayList对象且不需要这段可疑的static代码了吗?

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值