How to sort CopyOnWriteArrayList

懵懂的女人 提交于 2019-12-03 14:22:42

问题


I want to sort CopyOnWriteArrayList. Currently it is throwing unsorted operation exception.

  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)  

Thanks in advance.


回答1:


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



回答2:


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.




回答3:


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



回答4:


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.



来源:https://stackoverflow.com/questions/28805283/how-to-sort-copyonwritearraylist

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!