【问题标题】:How to sort CopyOnWriteArrayList如何对 CopyOnWriteArrayList 进行排序
【发布时间】:2015-03-02 08:21:59
【问题描述】:

我想对CopyOnWriteArrayList 进行排序。但是当我尝试运行以下代码时

它正在抛出unsorted operation exception

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)  

提前致谢。

【问题讨论】:

  • 我怀疑堆栈跟踪比这更长 - 显示失败的操作...
  • 我建议将其复制到ArrayList,排序并复制回来。
  • 是的,堆栈跟踪更长。让我编辑并放一个完整的跟踪。
  • @talex- 这将导致非常昂贵的操作。

标签: java core copyonwritearraylist


【解决方案1】:

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

【讨论】:

    【解决方案2】:

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

    【讨论】:

      【解决方案3】:

      在JDK1.8中可以直接使用sort(Comparator&lt;? super E&gt; 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;
          }
      });
      

      【讨论】:

      • 这需要minSDK 24
      【解决方案4】:

      因为每次更改时 CopyOnWriteArrayList 都会复制自身,因此它的迭代器不允许您更改列表。如果是这样,Iterator 就不是线程安全的,线程安全是这个类的重点。 Collections.sort() 不起作用,因为它需要一个支持 set() 方法的迭代器。

      【讨论】:

        【解决方案5】:

        Kotlin 辅助函数

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

        在安卓上

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2016-02-19
          • 2011-11-09
          • 2014-04-18
          • 2016-05-17
          • 2016-11-24
          • 1970-01-01
          相关资源
          最近更新 更多