2015-03-02 58 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

我懷疑堆棧跟蹤長於 - 顯示失敗的操作... – 2015-03-02 08:23:16

+0

我建議把它複製到ArrayList中,排序和複製回。 – talex 2015-03-02 08:24:39

+0

是的,堆棧跟蹤更長。讓我編輯並放置一個完整的跟蹤。 – 2015-03-02 08:26:26

回答

7

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

由於CopyOnWriteArrayList在每次更改它時都會自我複製,因此它的Iterator不允許您對列表進行更改。如果是這樣,迭代器不會是線程安全的,線程安全是這個類的全部重點。 Collections.sort()將不起作用,因爲它需要一個支持方法的迭代器。

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 

的缺點是,如果併發線程讀取listaddAll(temp)之間clear()它會看到一個空列表與葉夫根尼的解決方案wheras它可能會看到一個部分排序的列表。

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