如何对 CopyOnWriteArrayList 进行排序
How to sort CopyOnWriteArrayList
我要排序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)
提前致谢。
因为每次更改 CopyOnWriteArrayList 时都会复制自身,所以它的迭代器不允许您更改列表。如果是这样,迭代器就不是线程安全的,而线程安全就是这个 class 的重点。 Collections.sort()
将不起作用,因为它需要支持 set()
方法的迭代器。
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]);
}
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 的解决方案,它可能会看到一个部分排序的列表。
在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;
}
});
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)
}
}
在 Android
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)
}
}
}
我要排序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)
提前致谢。
因为每次更改 CopyOnWriteArrayList 时都会复制自身,所以它的迭代器不允许您更改列表。如果是这样,迭代器就不是线程安全的,而线程安全就是这个 class 的重点。 Collections.sort()
将不起作用,因为它需要支持 set()
方法的迭代器。
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]);
}
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 的解决方案,它可能会看到一个部分排序的列表。
在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;
}
});
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)
}
}
在 Android
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)
}
}
}