1

刚刚看了一下 CopyOnWriteArrayList 类,我想知道为什么它的 get(...) 方法不需要任何同步。add(...) 和 set(...) 方法使用 ReentrantLock 更改互斥块中的底层数组。但是 get(...) 只是返回原始的底层数组,没有任何同步。好的,底层数组被声明为 volatile:

private volatile transient Object[] array;

但我不明白使用 volatile 如何使任何同步变得多余。它只防止存储在数组中的引用被编译器缓存。如果我明白为什么这里不需要同步,我可以用比以前少一点的锁竞争来编写我的代码......

谢谢,奥利弗

4

2 回答 2

1

它使用了一个小“技巧”​​——当底层数组改变时,事件的顺序是:

  1. 创建一个新数组
  2. 填充新数组
  3. 更改类持有的引用以指向新数组

第三步写入private volatile transient Object[] array;- 由于易失语义,在第三步之前所做的所有更改都是可见的。

因此,不仅新引用可见,而且新数组的内容也可见(这就是诀窍)。

于 2013-04-10T13:15:39.240 回答
1

线索就在名称中(正如 MarkRotteveel 指出的那样)。

当进行任何更改时,更改是单独进行的,Object[]然后整个批次被复制 - “写入时复制”。

由于内部Object[]volatile当引用从旧的更改为Object[]Object[]的时,所有线程都会接受更改。

于 2013-04-10T13:13:19.803 回答