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; }