- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
来自这个article ,它说:
When we areusing any of the modify methods – such as add() or remove() – thewhole content of the CopyOnWriteArrayList is copied into the newinternal copy.
Due to this simple fact, we can iterate over the list in a safe way,even when concurrent modification is happening.
When we're calling the iterator() method on the CopyOnWriteArrayList,we get back an Iterator backed up by the immutable snapshot of thecontent of the CopyOnWriteArrayList.
Its content is an exact copy of data that is inside an ArrayList fromthe time when the Iterator was created. Even if in the meantime someother thread adds or removes an element from the list, thatmodification is making a fresh copy of the data that will be used inany further data lookup from that list.
接下来要问自己的一个简单问题是为什么两者都是?基本上,根据我的理解,写入操作是在新副本上进行的,而读取操作是在集合的克隆上完成的。
例如,如果写入是在新副本上完成的,这意味着我可以迭代“原始”集合 - 这意味着它不会受到影响。那么为什么要增加在另一个副本(快照)中存储元素的开销呢?或者相反,如果我将元素存储在副本(快照)中,当我实际上是在克隆而不是“原始”集合(意味着快照永远不会改变)上迭代时,为什么需要在副本上进行写入?
我希望这个问题是合法的,因为我确实检查了互联网上所有可能的来源,但没有一篇文章能帮助我消除这种困惑。我在这里缺少什么?
最佳答案
当您调用 iterator
时,
CopyOnWriteArrayList
不会创建数组的副本,因为 docs说:
The "snapshot" style iterator method uses a reference to the state of the array at the point that the iterator was created.
注意“引用”这个词。
这句话的措辞相当糟糕:
Its content is an exact copy of data that is inside an ArrayList from the time when the Iterator was created.
这并不意味着在您调用 iterator()
时创建了数组的副本。应该说:
Its content is the same as the data that is inside an ArrayList from the time when the Iterator was created.
该段比较重要的一点是:
Even if in the meantime some other thread adds or removes an element from the list, that modification is making a fresh copy of the data that will be used in any further data lookup from that list.
这意味着如果您创建一个迭代器,然后继续以某种方式改变列表,迭代器将看不到这些更改。为什么?因为突变是通过创建一个具有突变的新数组来完成的,但是迭代器正在遍历没有突变的旧数组。这就是为什么我们说迭代器拍摄“快照”。
这里有一些来自 OpenJDK 的代码来说明。
在iterator()
,它只是创建了一个带有 getArray()
的 COWIterator
,它通过返回 volatile array
字段来获取快照:
final Object[] getArray() {
return array;
}
...
public Iterator<E> iterator() {
return new COWIterator<E>(getArray(), 0);
}
和增变器方法,例如add
,设置数组
字段:
final void setArray(Object[] a) {
array = a;
}
...
public boolean add(E e) {
Object[] elements = getArray();
int len = elements.length;
Object[] newElements = Arrays.copyOf(elements, len + 1);
newElements[len] = e;
setArray(newElements);
return true;
}
我删除了(解锁)锁定代码,以便更容易看到发生了什么。
关于java - 为什么 CopyOnWriteArrayList 需要写入和读取操作的副本?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66953297/
不确定我的标题措辞是否正确,但请耐心等待,所有内容都会得到解释... 我们有一组代码不是在这里发明的,它使用进程间通信(IPC 消息传递)。该方案的大致轮廓是这样的: comms.c 包含: stat
你怎么能列出所有的颠覆合并? 例如: Trunk ____9_____14____20___ \ \ \ \______\_____\___
是否有一个集合的标准 Java(1.5+)实现(即无第三方),允许我将多个集合粘合到一个集合中? 这是其工作原理的草图: final SomeCollection x = new SomeCollec
有没有办法让sql查询返回拆分行。我什至不知道怎么问。下面有'index_tag'。 select event.name, tb_ev.start_time, tb_ev.end_time from
我正在尝试使用 postgresql COPY 命令从 CSV 加载一些数据。诀窍是我想在用户标识(包含在 CSV 中)上实现 Multi-Tenancy 。加载 csv 时,是否有一种简单的方法告诉
我正在尝试使用 bash 脚本将文件复制到当前目录。 为了处理需要转义的路径,使用了一个变量,该变量被转义然后提供给 cp 命令。 cp 命令提示: usage: cp [-R [-H | -L |
我正在尝试每 20 毫秒向给定的 x 和 y 坐标添加一次 CAShapelayer。我希望形状在一秒钟内消失(就像示踪剂一样)。我创建的功能有效,形状在正确的位置创建并消失。但是我留下了额外的形状,
我是 Python 新手。我正在尝试创建一个程序来打印我通常每周手动打印的一组文档,但是我遇到了几个问题: 这是代码: import os file_list = os.listdir("C:/Pyt
我有一个大小为 10 的 ArrayList l1。我将 l1 分配给新的列表引用类型 l2。 l1 和 l2 会指向同一个 ArrayList 对象吗?或者是 ArrayList 对象的副本分配给
我这周花了一个自由职业者创建的 Mongo 4.4 PSA 副本来工作。我放弃了,从所有三台服务器上删除了完整的 mongod,然后按照 Mongo doc 从头开始安装。 .唯一的变化是在副本初
设置信息: 我有两个数据中心,每个 DC 中有 5 个节点。 我知道插入到表中的每一行都是根据使用的数据分区方案存储的;生成必要的副本并将它们存储在集群中的其他节点(根据复制策略选择节点)上。给定一行
我对 XSLT 完全陌生,所以请耐心等待。 我有两个 xml 文件,我试图使用 XSLT 将它们连接在一起。我想合并这些文件,以便第二个文件中指定的任何值覆盖第一个文件。例如 firstFile.xm
这里肯定有一个初学者问题,为什么 F# 编译器会制作不必要的 DateTimeOffset 副本,我该如何阻止它?我不记得这是个问题,但也许自从我在 F# 中使用 DateTimeOffset 以来已
我有一个用 C# 编写的 WinForms 应用程序,在将数据从 SQL 数据库导出到模板的工作表之前,它使用以下代码打开 Excel 模板。 Microsoft.Office.Interop.Exc
我从这个 post 得到的 xsl 中有这个函数 用“换行符”替换“cr” 我是这样调用它的: 我正在做文章链接,点击文本“阅读更多”
所以这可能有点难以解释...... 目前我这样做: SomeInterface xyz1 = SomeInterface.method(data); SomeInterfaceCopy xyz2 =
我有一个包含指针 p 的类型 var。我需要在另一个与 var 类型相同的变量 var1 上复制 var(通过在引号中执行 var1 "="var,因为我不知道这是否是正确的方法,请参见下文)。 在我
出于某种原因,我需要同时运行两个 xampp 副本。我在互联网上阅读了很多教程,但如果我需要运行另一个,他们最终会告诉我关闭当前的 xampp。这有可能实现吗? 最佳答案 您可以使用不同的端口同时运行
在aws中,“upload-part-copy”具有字节范围选项。如果我想将两个对象的一部分复制到云中的新对象,我可以使用“upload-part-copy”命令进行复制。 我找不到任何此类方法或机制
我有一个带栏的表 foo foo --- bar 我使用 Postgres 的 Copy 命令 COPY (select * from foo) TO 'complete_file_path' WIT
我是一名优秀的程序员,十分优秀!