如何对CopyOnWriteArrayList进行排序

时间:2015-03-02 08:21:59

标签: java core copyonwritearraylist

我想对CopyOnWriteArrayList进行排序。目前它正在抛出未排序的操作异常。

  import java.util.Collections;
  import java.util.List;
  import java.util.concurrent.CopyOnWriteArrayList;

 public class CopyOnWriteArrayListExample {

  public static void main(final String[] args) {
     List<String> list = new CopyOnWriteArrayList<>();
    list.add("3");
    list.add("2");
    list.add("1");

    Collections.sort(list);
   }
}

Exception in thread "main" java.lang.UnsupportedOperationException
at java.util.concurrent.CopyOnWriteArrayList$COWIterator.set(CopyOnWriteArrayList.java:1049)
at java.util.Collections.sort(Collections.java:159)
at com.sac.list.CopyOnWriteArrayListExample.main(CopyOnWriteArrayListExample.java:15)  

提前致谢。

5 个答案:

答案 0 :(得分:9)

Collections.sort使用ListIterator.set

    ...
    for (int j=0; j<a.length; j++) {
        i.next();
        i.set((T)a[j]);
    }

但CopyOnWriteArrayList的ListIterator不支持删除,设置或添加方法。

解决方法:

    Object[] a = list.toArray();
    Arrays.sort(a);
    for (int i = 0; i < a.length; i++) {
        list.set(i, (String) a[i]);
    }

答案 1 :(得分:5)

在JDK1.8中可以直接使用sort(Comparator<? super E> c)

List<Integer> list = new CopyOnWriteArrayList<Integer>();

list.add(3);
list.add(4);
list.add(1);

list.sort(new Comparator<Integer>() {
    @Override
    public int compare(Integer o1, Integer o2) {
        return o1 - o2;
    }
});

答案 2 :(得分:4)

Evgeniy的解决方案以正确的方式指出,但list.set(i, (String) a[i])必须为列表中的每个元素锁定list。如果存在写入list的并发线程,则会显着减慢循环。

为了最大限度地减少阻塞,最好减少改变list的语句数量:

    CopyOnWriteArrayList<Integer> list = new CopyOnWriteArrayList<>();

    // ... fill list with values ...

    ArrayList<Integer> temp = new ArrayList<>();
    temp.addAll(list);                           
    Collections.sort(temp);

    list.clear();            // 1st time list is locked
    list.addAll(temp);       // 2nd time list is locked

缺点是,如果并发线程在listclear()之间读取addAll(temp),它将看到一个空列表,并且在Evgeniy的解决方案中它可能会看到部分排序的列表。

答案 3 :(得分:0)

因为CopyOnWriteArrayList每次更改时都会自行复制,因此其Iterator不允许您更改列表。如果确实如此,Iterator将不是线程安全的,并且线程安全是这个类的重点。 Collections.sort()无效,因为它需要支持set()方法的迭代器。

答案 4 :(得分:0)

Kotlin助手功能

inline fun <T, R : Comparable<R>> CopyOnWriteArrayList<T>.sortListBy(crossinline selector: (T) -> R?) {
    if (size > 1) {
        val list = ArrayList(this)
        list.sortBy(selector)
        clear()
        addAll(list)
    }
}

在Android上

inline fun <T, R : Comparable<R>> CopyOnWriteArrayList<T>.sortListBy(crossinline selector: (T) -> R?) {
    if (size > 1) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            sortBy(selector)
        } else {
            val list = ArrayList(this)
            list.sortBy(selector)
            clear()
            addAll(list)
        }
    }
}