How to sort CopyOnWriteArrayList

前端 未结 5 1494
名媛妹妹
名媛妹妹 2021-02-06 08:46

I want to sort CopyOnWriteArrayList. But when I tried to run the following code

It is throwing unsorted operation exception.



        
相关标签:
5条回答
  • 2021-02-06 09:15

    Collections.sort uses ListIterator.set

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

    but CopyOnWriteArrayList's ListIterator does not support the remove, set or add methods.

    Workaround:

        Object[] a = list.toArray();
        Arrays.sort(a);
        for (int i = 0; i < a.length; i++) {
            list.set(i, (String) a[i]);
        }
    
    0 讨论(0)
  • 2021-02-06 09:16

    In JDK1.8 can use sort(Comparator<? super E> c) directly.

    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;
        }
    });
    
    0 讨论(0)
  • 2021-02-06 09:18

    Evgeniy's solution points in the right way, but list.set(i, (String) a[i]) has to gain the lock on list for each element in the list. If there is a concurrent thread which writes into list this will slow down the loop dramatically.

    To minimize blocking it's better to reduce the number of statements which alter 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
    

    The downside is that if a concurrent thread reads list between clear() and addAll(temp) it will see an empty list wheras with Evgeniy's solution it may see a partially sorted list.

    0 讨论(0)
  • 2021-02-06 09:37

    Because a CopyOnWriteArrayList copies itself every time you change it, its Iterator doesn't allow you to make changes the list. If it did, the Iterator would not be thread safe, and thread safety is the whole point of this class. Collections.sort() won't work as it requires an Iterator that supports the set() method.

    0 讨论(0)
  • 2021-02-06 09:39

    Kotlin helper function

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

    On 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)
            }
        }
    }
    
    0 讨论(0)
提交回复
热议问题