zoukankan      html  css  js  c++  java
  • CopyOnWriteArrayList集合排序异常问题

    1、集合自定义排序实现

    对List集合的自定义排序想必大家都知道要使用如下的方式,通过实现Comparator接口并实现compare方法来实现。

    /**
             * 
             * @方法名 changeChain
             * @描述    改变请求链
             * @参数
             * @返回类型 void
             * @作者 cymiao
             */
            public static void changeChain(Class<? extends Chain> type){
                List<? extends Chain> list = DynamicLoader.getInstance().getChainList(type);
                Collections.sort(list, new Comparator<Chain>(){
    
                    @Override
                    public int compare(Chain chain1, Chain chain2) {
                        int orderO = ((OrderAnnotation)chain1.getClass().getAnnotation(OrderAnnotation.class)).value();
                        int orderT = ((OrderAnnotation)chain2.getClass().getAnnotation(OrderAnnotation.class)).value();
                        if(orderO > orderT){
                            return 1;
                        }else if(orderO < orderT){
                            return -1;
                        }
                        return 0;
                    }
                    
                });
                List<Chain> aList = new CopyOnWriteArrayList<Chain>();
                aList.addAll(list);
                DynamicLoader.getInstance().setChainList(aList, type);
            }

    2、CopyOnWriteArrayList集合排序异常问题

    在不同版本的JDK时,CopyOnWriteArrayList集合使用如上方法排序的时候会抛出UnsupportedOperationException异常,这是为什么呢?下来让我们通过研究CopyOnWriteArrayList类的源码来说明这个问题:

    (1)、我们先来分析下JDK1.6中Collections.sort的实现逻辑

     如下JDK1.6的源码所示,在自定义排序时,先使用Arrays.sort对集合的Object数组进行排序,然后通过调用集合的listIterator()方法获取ListIterator对象,并调用对象的set(E e)方法赋值,我们再看CopyOnWriteArrayList集合的源码,发现listIterator()方法返回的是new COWIterator<E>(getArray(), 0);对象,而这个对象的set方法没有具体实现而是直接抛UnsupportedOperationException异常,所以问题很显而易见了,在JDK1.6版本下是不能对CopyOnWriteArrayList集合使用Comparator来进行自定义排序的。

    public static <T> void sort(List<T> paramList, Comparator<? super T> paramComparator)
      {
        Object[] arrayOfObject = paramList.toArray();
        Arrays.sort(arrayOfObject, paramComparator);
        ListIterator localListIterator = paramList.listIterator();
        for (int i = 0; i < arrayOfObject.length; i++) {
          localListIterator.next();
          localListIterator.set(arrayOfObject[i]);
        }
      }
    /**
         * {@inheritDoc}
         *
         * <p>The returned iterator provides a snapshot of the state of the list
         * when the iterator was constructed. No synchronization is needed while
         * traversing the iterator. The iterator does <em>NOT</em> support the
         * {@code remove}, {@code set} or {@code add} methods.
         */
        public ListIterator<E> listIterator() {
            return new COWIterator<E>(getArray(), 0);
        }
    
    static final class COWIterator<E> implements ListIterator<E> {
            /** Snapshot of the array */
            private final Object[] snapshot;
            /** Index of element to be returned by subsequent call to next.  */
            private int cursor;
    
            private COWIterator(Object[] elements, int initialCursor) {
                cursor = initialCursor;
                snapshot = elements;
            }
    
            public boolean hasNext() {
                return cursor < snapshot.length;
            }
    
            public boolean hasPrevious() {
                return cursor > 0;
            }
    
            @SuppressWarnings("unchecked")
            public E next() {
                if (! hasNext())
                    throw new NoSuchElementException();
                return (E) snapshot[cursor++];
            }
    
            @SuppressWarnings("unchecked")
            public E previous() {
                if (! hasPrevious())
                    throw new NoSuchElementException();
                return (E) snapshot[--cursor];
            }
    
            public int nextIndex() {
                return cursor;
            }
    
            public int previousIndex() {
                return cursor-1;
            }
    
            /**
             * 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();
            }
        }

    (2)、接下来我们分析下JDK1.8中Collections.sort的实现逻辑

    如下Collections类的源码所示,1.8版本中修改了集合排序的逻辑,不是直接在Collections类中排序,而是调用集合对象自己的sort方法实现排序了,在JDK1.6中CopyOnWriteArrayList是没有sort方法实现的,在1.8中添加了sort的实现,源码如下,集合的Object数组排序完成以后,直接把排序后的数据赋值给了集合中的Object数据,所以在JDK1.8中能对CopyOnWriteArrayList集合使用Comparator来进行自定义排序的。

    /**
         * Sorts the specified list according to the order induced by the
         * specified comparator.  All elements in the list must be <i>mutually
         * comparable</i> using the specified comparator (that is,
         * {@code c.compare(e1, e2)} must not throw a {@code ClassCastException}
         * for any elements {@code e1} and {@code e2} in the list).
         *
         * <p>This sort is guaranteed to be <i>stable</i>:  equal elements will
         * not be reordered as a result of the sort.
         *
         * <p>The specified list must be modifiable, but need not be resizable.
         *
         * @implNote
         * This implementation defers to the {@link List#sort(Comparator)}
         * method using the specified list and comparator.
         *
         * @param  <T> the class of the objects in the list
         * @param  list the list to be sorted.
         * @param  c the comparator to determine the order of the list.  A
         *        {@code null} value indicates that the elements' <i>natural
         *        ordering</i> should be used.
         * @throws ClassCastException if the list contains elements that are not
         *         <i>mutually comparable</i> using the specified comparator.
         * @throws UnsupportedOperationException if the specified list's
         *         list-iterator does not support the {@code set} operation.
         * @throws IllegalArgumentException (optional) if the comparator is
         *         found to violate the {@link Comparator} contract
         * @see List#sort(Comparator)
         */
        @SuppressWarnings({"unchecked", "rawtypes"})
        public static <T> void sort(List<T> list, Comparator<? super T> c) {
            list.sort(c);
        }
    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();
            }
        }
    
    /**
         * Sets the array.
         */
        final void setArray(Object[] a) {
            array = a;
        }
  • 相关阅读:
    [树莓派]wifi在面板看不到,但是可以scan到的解决方案
    关于GCD的几个结论
    Ubuntu配置vncserver
    树莓派更改vnc分辨率
    玩转树莓派
    两个树莓派(或香蕉派)之间的音频直播测试
    使用树莓派录音——USB声卡
    树莓派自定义命令(给命令起别名)
    gitlab搭建
    linux下的缓存机制及清理buffer/cache/swap的方法梳理 (转)
  • 原文地址:https://www.cnblogs.com/cymiao/p/8400421.html
Copyright © 2011-2022 走看看