标签: copyonwritearraylist

在暴露内部收集物品时是否应使用Iterator或Iterable?

我有一个包含私有可变数据列表的类.

我需要在以下条件下公开列表项:

  • 清单不应在外面修改;
  • 应该清楚使用getter函数的开发人员无法修改他们获得的列表.

应该将哪个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实现的最佳实践的真实代码审查讨论

java iterator iterable arraylist copyonwritearraylist

10
推荐指数
1
解决办法
513
查看次数

如何对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)  
Run Code Online (Sandbox Code Playgroud)

提前致谢.

java core copyonwritearraylist

6
推荐指数
3
解决办法
3786
查看次数

为什么CopyOnWriteArrayList使用getArray()来访问数组引用?

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)

java copyonwritearraylist

6
推荐指数
1
解决办法
144
查看次数

Java在不同的地方同时修改列表

我有这段代码,我使用迭代器遍历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)迭代这些命令并逐个执行它们,同时从列表中执行时删除它们.

  • 执行命令时,此命令可以依次向我的主类中保存的列表添加新命令.(这实际上有点复杂:处理命令要求客户端响应,而客户端的响应将响应命令,并且会将其添加到保存的列表中).

java iterator concurrentmodification copyonwritearraylist

3
推荐指数
1
解决办法
442
查看次数

为什么 CopyOnWriteArrayList 的写入和读取操作都需要副本?

来自这篇文章,它说:

\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

我希望这个问题是合法的,因为我确实检查了互联网上所有可能的来源,但没有一篇文章帮助我消除了这种困惑。我在这里缺少什么?

\n

java iterator clone copyonwritearraylist java-failsafe

3
推荐指数
1
解决办法
825
查看次数

同时合并列表 - CopyOnWriteArrayList 或 ConcurrentLinkedQueue 哪个更好?

支持有几个线程运行查询任务,每个线程都会返回一个list结果,哪种数据结构会更快地合并结果?

并发链接队列

基于链接节点的无界线程安全队列。该队列对元素进行 FIFO(先进先出)排序。队列的头部是在队列中停留时间最长的元素。队列的尾部是在队列中停留时间最短的元素。新元素插入到队列尾部,队列检索操作获取队列头部元素。当许多线程共享对公共集合的访问时,ConcurrentLinkedQueue 是一个合适的选择。与大多数其他并发集合实现一样,此类不允许使用 null 元素。 该实现采用了一种高效的“无等待”算法,该算法基于 Maged M. Michael 和 Michael L. Scott 的《简单、快速和实用的非阻塞和阻塞并发队列算法》中描述的算法。

写入数组列表时复制

顾名思义,CopyOnWriteArrayList 使用每个突变操作(例如添加或设置)创建底层 ArrayList 的副本。通常,CopyOnWriteArrayList 非常昂贵,因为它在每次写入操作时都涉及昂贵的数组复制,但如果您有一个迭代次数超过突变的列表,则它非常有效,例如您主要需要迭代 ArrayList 并且不要太频繁地修改它。

java concurrency multithreading java.util.concurrent copyonwritearraylist

2
推荐指数
1
解决办法
2123
查看次数

迭代CopyOnWriteArrayList时出现UnsupportedOperationException

我在一本书中看到了以下陈述:

任何基于写入复制IteratorListIterator(例如添加,设置或删除)调用的变异方法都会抛出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方法修改给定时没有得到异常?

java collections concurrency iterator copyonwritearraylist

2
推荐指数
1
解决办法
212
查看次数

了解CopyOnWriteArrayList迭代器行为

我正在学习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)

我相信,我在这里缺乏了解。有人可以帮忙吗?

java copyonwritearraylist

1
推荐指数
1
解决办法
57
查看次数

CopyOnWriteArrayList 太慢

我有以下案例,

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_NUMBER10_00_000的程序继续运行并且永远不会结束(它会,但我不能等这么久)。

我认为Collections.synchronizedList当您想要线程安全和速度时这是更好的选择。我用了它,花了大约0.007673728

我的问题:

  1. 为什么它在内部创建新数组,线程安全与此有关吗?
  2. 为什么在这种情况下要花这么多时间 …

java performance thread-safety copyonwritearraylist

0
推荐指数
1
解决办法
2260
查看次数

是否有 Java CopyOnWriteArrayList 实现的改进替代方案以及如何请求更改 Java 规范?

CopyOnWriteArrayList 几乎具有我想要的行为,如果删除不必要的副本,它将正是我正在寻找的。特别是,它可以像 ArrayList 一样在 ArrayList 末尾进行添加 - 即,没有理由每次都创建一个新副本,这是非常浪费的。它实际上可以限制 ArrayList 的末尾来为读者捕获快照,并在添加新项目后更新末尾。

这种增强似乎是值得拥有的,因为对于许多应用程序来说,最常见的添加类型是添加到 ArrayList 的末尾 - 这甚至是选择使用 ArrayList 的一个原因。

也不会有额外的开销,因为它只能在附加时不复制,尽管它仍然需要检查是否需要重新调整大小,但 ArrayList 无论如何都必须这样做。

  1. 是否有任何替代实现或数据结构具有这种行为,而无需在末尾添加不必要的副本(即,线程安全且经过优化以允许频繁读取,而写入仅在列表末尾添加)?

  2. 如何提交更改请求以请求对 Java 规范进行更改,以消除在 CopyOnWriteArrayList 末尾添加的副本(除非需要重新调整大小)?

我真的很希望看到核心 Java 库对此进行更改,而不是维护和使用我自己的自定义代码。

java copyonwritearraylist

-1
推荐指数
1
解决办法
2936
查看次数