如何对 CopyOnWriteArrayList 进行排序

How to sort CopyOnWriteArrayList

我要排序CopyOnWriteArrayList。但是当我尝试 运行 以下代码时

正在投掷unsorted operation exception

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)  

提前致谢。

因为每次更改 CopyOnWriteArrayList 时都会复制自身,所以它的迭代器不允许您更改列表。如果是这样,迭代器就不是线程安全的,而线程安全就是这个 class 的重点。 Collections.sort() 将不起作用,因为它需要支持 set() 方法的迭代器。

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

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

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

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

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