我有一个包含私有可变数据列表的类.
我需要在以下条件下公开列表项:
应该将哪个getter函数标记为推荐方法?或者你能提供更好的解决方案吗?
class DataProcessor {
private final ArrayList<String> simpleData = new ArrayList<>();
private final CopyOnWriteArrayList<String> copyData = new CopyOnWriteArrayList<>();
public void modifyData() {
...
}
public Iterable<String> getUnmodifiableIterable() {
return Collections.unmodifiableCollection(simpleData);
}
public Iterator<String> getUnmodifiableIterator() {
return Collections.unmodifiableCollection(simpleData).iterator();
}
public Iterable<String> getCopyIterable() {
return copyData;
}
public Iterator<String> getCopyIterator() {
return copyData.iterator();
}
}
Run Code Online (Sandbox Code Playgroud)
UPD:这个问题来自关于列表getter实现的最佳实践的真实代码审查讨论
我想对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)
Run Code Online (Sandbox Code Playgroud)
提前致谢.
CopyOnWriteArrayList中的几乎所有方法都使用getArray()来直接吸引数组.这种行为有原因吗?例如 :
public int size() {
return getArray().length;
}
Run Code Online (Sandbox Code Playgroud)
要么
public int indexOf(Object o) {
Object[] elements = getArray();
return indexOf(o, elements, 0, elements.length);
}
Run Code Online (Sandbox Code Playgroud) 我有这段代码,我使用迭代器遍历ArrayList,如:
Iterator iterator = list.iterator();
while (iterator.hasNext()) {
Element element = iterator.next();
iterator.remove();
handle(element)
}
Run Code Online (Sandbox Code Playgroud)
其中'handle(元素元素)`如下:
ListIterator iterator = list.listiterator();
iterator.add(element);
Run Code Online (Sandbox Code Playgroud)
现在这给出了ConcurrentModificationException,因为iterator第一个方法中没有使用新添加的元素更新.
我目前使用CopyOnWriteArrayList解决了这个问题,但这些对性能来说非常昂贵.有没有更好的方法来解决这个问题?
提前致谢!
(注意:这个例子没有任何意义,但是用来说明我面对的是什么)
我会试着解释为什么我这样做:
我在主类中有一个需要执行的'命令'列表
我有一个while循环(示例中的代码1)迭代这些命令并逐个执行它们,同时从列表中执行时删除它们.
执行命令时,此命令可以依次向我的主类中保存的列表添加新命令.(这实际上有点复杂:处理命令要求客户端响应,而客户端的响应将响应命令,并且会将其添加到保存的列表中).
来自这篇文章,它说:
\n\n\n当我们\n使用任何修改方法\xe2\x80\x93(例如add()或remove()\xe2\x80\x93)时,\nCopyOnWriteArrayList的整个内容都会被复制到新的\n内部副本中。
\n由于这个简单的事实,我们可以以安全的方式迭代列表,\n即使发生并发修改也是如此。
\n当我们在 CopyOnWriteArrayList 上调用 iterator() 方法时,我们会返回一个由 CopyOnWriteArrayList 内容的不可变快照备份的迭代器。
\n它的内容是创建迭代器时 ArrayList 内数据的精确副本。\n 即使与此同时,某个线程从列表中添加或删除元素,该修改也会创建数据的新副本,该副本将用于从该列表进行任何进一步的数据查找。
\n
接下来要问自己的简单问题是为什么两者都是?基本上,根据我的理解,写入操作是在新副本上进行的,而读取操作是在集合的克隆上完成的。
\n例如,如果在新副本上完成写入,则意味着我可以迭代“原始”集合 - 这意味着它不会受到影响。那么为什么要增加在另一个副本(快照)中存储元素的开销呢?或者相反的方向,如果我将元素存储在副本(快照)中,为什么当我实际上是在克隆而不是“原始”集合上迭代时需要在副本上进行写入(意味着快照永远不会改变)?
\n我希望这个问题是合法的,因为我确实检查了互联网上所有可能的来源,但没有一篇文章帮助我消除了这种困惑。我在这里缺少什么?
\n支持有几个线程运行查询任务,每个线程都会返回一个list结果,哪种数据结构会更快地合并结果?
基于链接节点的无界线程安全队列。该队列对元素进行 FIFO(先进先出)排序。队列的头部是在队列中停留时间最长的元素。队列的尾部是在队列中停留时间最短的元素。新元素插入到队列尾部,队列检索操作获取队列头部元素。当许多线程共享对公共集合的访问时,ConcurrentLinkedQueue 是一个合适的选择。与大多数其他并发集合实现一样,此类不允许使用 null 元素。 该实现采用了一种高效的“无等待”算法,该算法基于 Maged M. Michael 和 Michael L. Scott 的《简单、快速和实用的非阻塞和阻塞并发队列算法》中描述的算法。
顾名思义,CopyOnWriteArrayList 使用每个突变操作(例如添加或设置)创建底层 ArrayList 的副本。通常,CopyOnWriteArrayList 非常昂贵,因为它在每次写入操作时都涉及昂贵的数组复制,但如果您有一个迭代次数超过突变的列表,则它非常有效,例如您主要需要迭代 ArrayList 并且不要太频繁地修改它。
java concurrency multithreading java.util.concurrent copyonwritearraylist
我在一本书中看到了以下陈述:
任何基于写入复制
Iterator或ListIterator(例如添加,设置或删除)调用的变异方法都会抛出UnsupportedOperationException.
但是,当我运行以下代码时,它工作正常,并没有抛出UnsupportedOperationException.
List<Integer> list = new CopyOnWriteArrayList<>(Arrays.asList(4, 3, 52));
System.out.println("Before " + list);
for (Integer item : list) {
System.out.println(item + " ");
list.remove(item);
}
System.out.println("After " + list);
Run Code Online (Sandbox Code Playgroud)
上面的代码给出了以下结果:
Before [4, 3, 52]
4
3
52
After []
Run Code Online (Sandbox Code Playgroud)
为什么我在list使用该remove方法修改给定时没有得到异常?
我正在学习CopyOnWriteArrayList,下面的情况让我思考。
我的主要方法如下:
public static void main(String[] args) {
List<String> list = new CopyOnWriteArrayList<String>();
list.add("Init1");
list.add("Init2");
list.add("Init3");
list.add("Init4");
for(String str : list){
System.out.println(str);
list.add("PostInit");
}
}
Run Code Online (Sandbox Code Playgroud)
在javadoc中,我读到:
内存一致性影响:与其他并发集合一样,在将对象放入CopyOnWriteArrayList之前在线程中执行的操作发生在访问或从另一个线程中的CopyOnWriteArrayList删除该元素之后的操作之前。
我一直期待一个无限循环,因为“在将对象放入CopyOnWriteArrayList之前,线程中的操作发生在访问或删除之后的操作之前”。
但是我的控制台输出是:
Init1
Init2
Init3
Init4
Run Code Online (Sandbox Code Playgroud)
我相信,我在这里缺乏了解。有人可以帮忙吗?
我有以下案例,
public class Test {
private static final int MAX_NUMBER = 10_00_00;
public static void main(String[] args) {
List<Integer> list = new CopyOnWriteArrayList<>();
long start = System.nanoTime();
for(int i = 0; i < MAX_NUMBER; i++) {
list.add(i * 2);
}
long end = System.nanoTime();
System.out.println(((end - start) / Math.pow(10, 9)));
}
}
Run Code Online (Sandbox Code Playgroud)
输出
6.861539857
Run Code Online (Sandbox Code Playgroud)
与大约花费的时间相比,它添加元素的速度相当慢。我在文档中知道了原因,ArrayList0.004690843
一种线程安全的变体,
ArrayList其中所有可变操作(添加、设置等)都是通过制作底层数组的新副本来实现的。
所以,我的理解是,每当我在此列表中添加新元素时,它都会创建新的新数组并在该数组的最后一个索引处添加元素。我发现add方法中有一个锁,除此之外,该方法实际上每次都创建新的数组。
当我增加到MAX_NUMBER我10_00_000的程序继续运行并且永远不会结束(它会,但我不能等这么久)。
我认为Collections.synchronizedList当您想要线程安全和速度时这是更好的选择。我用了它,花了大约0.007673728。
我的问题:
CopyOnWriteArrayList 几乎具有我想要的行为,如果删除不必要的副本,它将正是我正在寻找的。特别是,它可以像 ArrayList 一样在 ArrayList 末尾进行添加 - 即,没有理由每次都创建一个新副本,这是非常浪费的。它实际上可以限制 ArrayList 的末尾来为读者捕获快照,并在添加新项目后更新末尾。
这种增强似乎是值得拥有的,因为对于许多应用程序来说,最常见的添加类型是添加到 ArrayList 的末尾 - 这甚至是选择使用 ArrayList 的一个原因。
也不会有额外的开销,因为它只能在附加时不复制,尽管它仍然需要检查是否需要重新调整大小,但 ArrayList 无论如何都必须这样做。
是否有任何替代实现或数据结构具有这种行为,而无需在末尾添加不必要的副本(即,线程安全且经过优化以允许频繁读取,而写入仅在列表末尾添加)?
如何提交更改请求以请求对 Java 规范进行更改,以消除在 CopyOnWriteArrayList 末尾添加的副本(除非需要重新调整大小)?
我真的很希望看到核心 Java 库对此进行更改,而不是维护和使用我自己的自定义代码。
java ×10
iterator ×4
concurrency ×2
arraylist ×1
clone ×1
collections ×1
core ×1
iterable ×1
performance ×1