zoukankan      html  css  js  c++  java
  • CopyOnWriteArrayList源码

    实现List、RandomAccess、Cloneable
    List接口定义List集合的操作方法
    RandomAccess实现此接口的类可以随机访问
    Cloneable实现此接口的类可以进行拷贝操作
     
    重要说明:
    CopyOnWriteArrayList是线程安全的,
    通过CopyOnWriteArrayList对象中修改方法进行加锁,保证集合的线程安全
    同时对数组进行修改时,把当前对象的数组拷贝一份newElements,先对newElements进行操作,操作完再复制给对象的数组,减少对查询类操作的锁定
     
    代码翻译:
    public class CopyOnWriteArrayList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable {
        private static final long serialVersionUID = 8673264195747942595L;
    
        保护设置属性方法的锁
        final transient ReentrantLock lock = new ReentrantLock();
    
        只能通过getArray/setArray访问的数组
        private transient volatile Object[] array;
    
    
        获得数组,不是私有方法所以可以从CopyOnWriteArraySet访问
        final Object[] getArray() {
            return array;
        }
    
        设置数组
        final void setArray(Object[] a) {
            array = a;
        }
    
        创建一个空数组
        public CopyOnWriteArrayList() {
            setArray(new Object[0]);
        }
    
        
        根据指定的集合创建一个包含所有元素的数组
        主要方法是 Arrays.copyOf()
        public CopyOnWriteArrayList(Collection<? extends E> c) {
            Object[] elements;
            if (c.getClass() == CopyOnWriteArrayList.class)
                elements = ((CopyOnWriteArrayList<?>)c).getArray();
            else {
                elements = c.toArray();
                // c.toArray might (incorrectly) not return Object[] (see 6260652)
                if (elements.getClass() != Object[].class)
                    elements = Arrays.copyOf(elements, elements.length, Object[].class);
            }
            setArray(elements);
        }
    
        创建一个包含给定数组副本的列表。
        public CopyOnWriteArrayList(E[] toCopyIn) {
            setArray(Arrays.copyOf(toCopyIn, toCopyIn.length, Object[].class));
        }
        
        返回数组大小
        public int size() {
            return getArray().length;
        }
    
        判断数组是否为空
        public boolean isEmpty() {
            return size() == 0;
        }
    
        判断o1与o2是否相等
        private static boolean eq(Object o1, Object o2) {
            return (o1 == null) ? o2 == null : o1.equals(o2);
        }
    
    
        indexOf的静态版本,允许重复调用而不需要每次重新获得数组
        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;
            } else {
                for (int i = index; i < fence; i++)
                    if (o.equals(elements[i]))
                        return i;
            }
            return -1;
        }
    
        lastIndexOf的静态版本
        private static int lastIndexOf(Object o, Object[] elements, int index) {
            if (o == null) {
                for (int i = index; i >= 0; i--)
                    if (elements[i] == null)
                        return i;
            } else {
                for (int i = index; i >= 0; i--)
                    if (o.equals(elements[i]))
                        return i;
            }
            return -1;
        }
    
      
        如果数组中包含指定元素,则返回true
        public boolean contains(Object o) {
            Object[] elements = getArray();
            return indexOf(o, elements, 0, elements.length) >= 0;
        }
    
        根据对象获得索引位置
        public int indexOf(Object o) {
            Object[] elements = getArray();
            return indexOf(o, elements, 0, elements.length);
        }
    
      
        返回从index索引开始,对象E第一次出现的索引位置,如果没有返回-1
        public int indexOf(E e, int index) {
            Object[] elements = getArray();
            return indexOf(e, elements, index, elements.length);
        }
    
        从后开始检索对象o第一次出现的位置
        public int lastIndexOf(Object o) {
            Object[] elements = getArray();
            return lastIndexOf(o, elements, elements.length - 1);
        }
    
        返回从index索引反向开始,对象E第一次出现的索引位置,如果没有返回-1
        public int lastIndexOf(E e, int index) {
            Object[] elements = getArray();
            return lastIndexOf(e, elements, index);
        }
    
        拷贝一个CopyOnWriteArrayList对象镜像,里面的数组不会被拷贝,原对象中数组与拷贝对象中数组存储在相同的堆
        重点说明在方法中调用了clone.resetLock()方法,对ReentrantLock锁进行了重置
        public Object clone() {
            try {
                @SuppressWarnings("unchecked")
                CopyOnWriteArrayList<E> clone =
                    (CopyOnWriteArrayList<E>) super.clone();
                clone.resetLock();
                return clone;
            } catch (CloneNotSupportedException e) {
                // this shouldn't happen, since we are Cloneable
                throw new InternalError();
            }
        }
    
        返回数组
        public Object[] toArray() {
            Object[] elements = getArray();
            return Arrays.copyOf(elements, elements.length);
        }
    
        
        返回指定参数类型的数组对象,
        @SuppressWarnings("unchecked")
        public <T> T[] toArray(T a[]) {
            Object[] elements = getArray();
            int len = elements.length;
            //如果T数组长度小于调用方数组长度,则在调用方数组中截取长度为T的新数组
            if (a.length < len)
                return (T[]) Arrays.copyOf(elements, len, a.getClass());
            else {//如果T数组长度大于等于调用方数组长度,则新分配一个数组
                System.arraycopy(elements, 0, a, 0, len);
                if (a.length > len)
                    a[len] = null;
                return a;
            }
        }
    
        返回数组中指定索引的值
        @SuppressWarnings("unchecked")
        private E get(Object[] a, int index) {
            return (E) a[index];
        }
    
        返回指定索引的值
        public E get(int index) {
            return get(getArray(), index);
        }
    
      
        把指定索引位置的元素值替换为element
        重点说明:
        public E set(int index, E element) {
            final ReentrantLock lock = this.lock;
            //第一步先获得锁
            lock.lock();
            try {
                //定义临时数组变量
                Object[] elements = getArray();
                //从elements获得index索引的值,oldValue
                E oldValue = get(elements, index);
                //判断oldValue与newValue是否相等
                //【if语句一定会执行,不会执行else】
                //如果不相等,生成新的数组
                if (oldValue != element) {
                    int len = elements.length;
                    /拷贝当前数组对象,重新分配内存创建新数组对象newElements
                    Object[] newElements = Arrays.copyOf(elements, len);
                    newElements[index] = element;
                    //将newElements重新复制给当前对象的数组变量
                    setArray(newElements);
                } else {
                    // Not quite a no-op; ensures volatile write semantics
                    setArray(elements);
                }
                return oldValue;
            } finally {
                //释放锁
                lock.unlock();
            }
        }
    
        //添加对象e
        public boolean add(E e) {
            final ReentrantLock lock = this.lock;
            //第一步先获得锁
            lock.lock();
            try {
                //定义临时数组变量
                Object[] elements = getArray();
                int len = elements.length;
                //拷贝当前数组对象,重新分配内存创建新数组对象newElements
                Object[] newElements = Arrays.copyOf(elements, len + 1);
                newElements[len] = e;
                setArray(newElements);
                return true;
            } finally {
                //释放锁
                lock.unlock();
            }
        }
    
    
        在数组指定索引插入Element对象,如果index位置有值,则原有值向右移动
        public void add(int index, E element) {
            final ReentrantLock lock = this.lock;
            //第一步先获得锁
            lock.lock();
            try {
                //定义临时数组变量
                Object[] elements = getArray();
                int len = elements.length;
                if (index > len || index < 0)
                    throw new IndexOutOfBoundsException("Index: "+index+
                                                        ", Size: "+len);
                Object[] newElements;
                int numMoved = len - index;
                if (numMoved == 0)
                    //拷贝当前数组对象,重新分配内存创建新数组对象newElements
                    newElements = Arrays.copyOf(elements, len + 1);
                else {
                    //使用System.arraycopy()方法进行数组间的拷贝
                    newElements = new Object[len + 1];
                    System.arraycopy(elements, 0, newElements, 0, index);
                    System.arraycopy(elements, index, newElements, index + 1,
                                     numMoved);
                }
                newElements[index] = element;
                setArray(newElements);
            } finally {
                //释放锁
                lock.unlock();
            }
        }
    
        删除指定index位置的数据
        public E remove(int index) {
            final ReentrantLock lock = this.lock;
            //第一步先获得锁
            lock.lock();
            try {
                //定义临时数组变量
                Object[] elements = getArray();
                int len = elements.length;
                //获得oldValue
                E oldValue = get(elements, index);
                int numMoved = len - index - 1;
                //numMoved == 0代表index为数组最后一位
                if (numMoved == 0)
                    //拷贝当前数组对象,重新分配内存创建新数组对象
                    setArray(Arrays.copyOf(elements, len - 1));
                else {
                    //如果index为非数组最后一位,则新建一个长度减一的数组,通过System.arraycopy()方式进行拷贝
                    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();
            }
        }
    
        
        删除对象o第一次出现的数组
        public boolean remove(Object o) {
            Object[] snapshot = getArray();
            int index = indexOf(o, snapshot, 0, snapshot.length);
            return (index < 0) ? false : remove(o, snapshot, index);
        }
    
        从snapshot数组中删除指定index位置的数据
        private boolean remove(Object o, Object[] snapshot, int index) {
            final ReentrantLock lock = this.lock;
            //第一步先获得锁
            lock.lock();
            try {
                //定义临时数组变量
                Object[] current = getArray();
                int len = current.length;
                if (snapshot != current) findIndex: {
                    int prefix = Math.min(index, len);
                    for (int i = 0; i < prefix; i++) {
                        if (current[i] != snapshot[i] && eq(o, current[i])) {
                            index = i;
                            break findIndex;
                        }
                    }
                    if (index >= len)
                        return false;
                    if (current[index] == o)
                        break findIndex;
                    index = indexOf(o, current, index, len);
                    if (index < 0)
                        return false;
                }
                Object[] newElements = new Object[len - 1];
                System.arraycopy(current, 0, newElements, 0, index);
                System.arraycopy(current, index + 1,
                                 newElements, index,
                                 len - index - 1);
                setArray(newElements);
                return true;
            } finally {
                lock.unlock();
            }
        }
    
        如果对象e不存在,则添加对象e
        public boolean addIfAbsent(E e) {
            Object[] snapshot = getArray();
            return indexOf(e, snapshot, 0, snapshot.length) >= 0 ? false :
                addIfAbsent(e, snapshot);
        }
    
        在snapshot数组中添加对象e
        private boolean addIfAbsent(E e, Object[] snapshot) {
            final ReentrantLock lock = this.lock;
            lock.lock();
            try {
                Object[] current = getArray();
                int len = current.length;
                if (snapshot != current) {
                    // Optimize for lost race to another addXXX operation
                    int common = Math.min(snapshot.length, len);
                    for (int i = 0; i < common; i++)
                        if (current[i] != snapshot[i] && eq(e, current[i]))
                            return false;
                    if (indexOf(e, current, common, len) >= 0)
                            return false;
                }
                Object[] newElements = Arrays.copyOf(current, len + 1);
                newElements[len] = e;
                setArray(newElements);
                return true;
            } finally {
                lock.unlock();
            }
        }
        
        //把空数组复制给对象
        public void clear() {
            final ReentrantLock lock = this.lock;
            lock.lock();
            try {
                setArray(new Object[0]);
            } finally {
                lock.unlock();
            }
        }
        
        //对数组进行排序,先创建一个新的数组,对新数组排序后,新数组复制给对象
        public void sort(Comparator<? super E> c) {
            final ReentrantLock lock = this.lock;
            lock.lock();
            try {
                Object[] elements = getArray();
                Object[] newElements = Arrays.copyOf(elements, elements.length);
                @SuppressWarnings("unchecked") E[] es = (E[])newElements;
                Arrays.sort(es, c);
                setArray(newElements);
            } finally {
                lock.unlock();
            }
        }
    }
    收藏文章数量从多到少与“把书读薄”是一个道理
  • 相关阅读:
    sql server 中隐藏掉无关数据库
    Web Deploy自动配置
    jQuery form表单序列化为JSON对象!
    CURL HELP
    sql server生成递归日期、连续数据
    MVC项目中,如何访问Views目录下的静态文件!
    DDNS动态更新
    佛祖保佑 永无bug
    asp.net webservice返回json问题
    asp.net使用Get请求webservice
  • 原文地址:https://www.cnblogs.com/use-D/p/9627873.html
Copyright © 2011-2022 走看看