2015-03-02 1 views
4

Я хочу сортировать 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) 

Заранее благодарен.

+0

Я подозреваю, что трассировка стека больше, чем - показывает операцию, не удалось ... –

+0

я предлагаю скопировать его в ArrayList, сортировать и копировать обратно. – talex

+0

Да, трассировка стека длиннее. Позвольте мне отредактировать и поставить полный след. –

ответ

7

Collections.sort использует ListIterator.set

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

но ListIterator CopyOnWriteArrayList не поддерживает в удалить, установить или добавить методы.

Обход:

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

Поскольку экземпляр CopyOnWriteArrayList копирует себя каждый раз при его изменении, его Iterator не позволяет вам вносить изменения в список. Если бы это было так, то Итератор не был бы потокобезопасным, и безопасность потоков - это весь смысл этого класса. Collections.sort() не будет работать, поскольку для этого требуется Итератор, который поддерживает метод set().

2

точка решения Евгения находится в правильном направлении, но 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 

Недостатком является то, что если одновременно поток читает list между clear() и addAll(temp) он будет видеть пустой список Тогда как с решением Evgeniy в он может видеть частично отсортированный список.

2

В 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>() { 
 
\t @Override 
 
\t public int compare(Integer o1, Integer o2) { 
 
\t \t return o1 - o2; 
 
\t } 
 
});

Смежные вопросы