java 如何对CopyOnWriteArrayList进行排序?

lpwwtiir  于 4个月前  发布在  Java
关注(0)|答案(5)|浏览(61)

我想对CopyOnWriteArrayList进行排序。但是下面的代码抛出了一个UnsupportedOperationException

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

个字符
如何对CopyOnWriteArrayList进行排序?

9jyewag0

9jyewag01#

sort使用ListIterator.set

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

字符串
但CopyOnWriteArrayList的ListIterator不支持remove、set或add方法。
解决方法:

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

pnwntuvh

pnwntuvh2#

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的解决方案可能会看到一个部分排序的列表。

zbwhf8kr

zbwhf8kr3#

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

字符串

zynd9foi

zynd9foi4#

因为CopyOnWriteArrayList在每次你修改它的时候都会复制它自己,它的Iterator不允许你修改列表。如果它允许,Iterator就不是线程安全的,而线程安全是这个类的全部意义。Collections.sort()将不工作,因为它需要一个支持set()方法的Iterator。

6ioyuze2

6ioyuze25#

从Java 8开始,给定的代码无一例外地工作。
在Java 8之前的版本中,Collections.sort在给定列表的ListIterator上使用ListIterator.set,转发该方法抛出的任何UnsupportedOperationException

CopyOnWriteArrayList

不支持对迭代器本身(removesetadd)的元素更改操作。这些方法抛出UnsupportedOperationException
从Java 8开始,Collections.sort委托给新添加的List.sort方法。CopyOnWriteArrayList使用与之一起工作的自定义实现重写此方法。因此,Java 8版本的Collections.sort成功地对列表进行排序,而不是像Java的早期版本那样抛出异常。

Collections.sort
实施说明:

此实现遵循List.sort(Comparator)方法,使用指定的列表和比较器。

相关问题