`
MauerSu
  • 浏览: 495127 次
  • 性别: Icon_minigender_1
  • 来自: 北京
文章分类
社区版块
存档分类
最新评论

CopyOnWriteArrayList类set方法疑惑?

 
阅读更多
源:http://ifeve.com/copyonwritearraylist-set/
评:
在淘宝内网有位同事提了一个很好的问题,大家能否帮忙解答下?

在CopyOnWriteArrayList类的set方法中有一段setArray(elements)代码,实际上这段代码并未对elements做任何改动,实现的volatile语意并不对CopyOnWriteArrayList实例产生任何影响,为什么还是要保留这行语句?见以下代码红体部分:

01
/** The array, accessed only via getArray/setArray. */
02
private volatile transient Object[] array;
03

04
/**
05
* Replaces the element at the specified position in this list with the
06
* specified element.
07
*
08
* @throws IndexOutOfBoundsException {@inheritDoc}
09
*/
10
public E set(int index, E element) {
11
    final ReentrantLock lock = this.lock;
12
    lock.lock();
13
    try {
14
        Object[] elements = getArray();
15
        E oldValue = get(elements, index);
16

17
        if (oldValue != element) {
18
            int len = elements.length;
19
            Object[] newElements = Arrays.copyOf(elements, len);
20
            newElements[index] = element;
21
            setArray(newElements);
22
        } else {
23
            // Not quite a no-op; ensures volatile write semantics
24
            setArray(elements);
25
        }
26
        return oldValue;
27
    } finally {
28
        lock.unlock();
29
    }
30
}
31

32
/**
33
* Sets the array.
34
*/
35
final void setArray(Object[] a) {
36
    array = a;
37
}
38

39
/**
40
* Gets the array.  Non-private so as to also be accessible
41
* from CopyOnWriteArraySet class.
42
*/
43
final Object[] getArray() {
44
    return array;
45
}
===================
我想我可能找到这个问题的答案了,虽然在set方法的的API文档中没有描述它包含的内存语义。但在jdk有个地方描述到了:http://docs.oracle.com/javase/7/docs/api/ 的最下方的几条,摘录过来如下:

The methods of all classes in java.util.concurrent and its subpackages extend these guarantees to higher-level synchronization. In particular:Actions in a thread prior to placing an object into any concurrent collection happen-before actions subsequent to the access or removal of that element from the collection in another thread.

中文版API中是这样描述的:

java.util.concurrent 中所有类的方法及其子包扩展了这些对更高级别同步的保证。尤其是: 线程中将一个对象放入任何并发 collection 之前的操作 happen-before 从另一线程中的 collection 访问或移除该元素的后续操作。

CopyOnWriteArrayList作为java.util.concurrent包中的类之一,当然它也要遵守这个约定。所以才在else里面加了一个 setArray(elements);来保证hb关系。


Ticmy
2013/01/16 1:01下午
登录以回复 引用
链接贴错了:http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/package-summary.html


Ticmy
2013/01/16 1:25下午
登录以回复 引用
这个hb意义何在?如下例子:a为非volatile的某基本类型变量,coal为CopyOnWriteArrayList对象
t1:
x:a = calValue;
y:coal.set….
———————
t2:
m:coal.get…
n:int tmp = a;

假设存在以上场景,如果能保证只会存在这样的轨迹:x,y,m,n.根据上述java API文档中的约定有hb(y,m),根据线程内的操作相关规定有hb(x,y),hb(m,n),根据hb的传递性读写a变量就有hb(x,n),所以t1对a的写操作对t2中a的读操作可见。如果CopyOnWriteArrayList的set的else里没有setArray(elements)的话,hb(y,m)就不再有了,上述的可见性也就无法保证。


michaelchan
2016/02/18 10:52上午
登录以回复 引用
的确是这样,实际上不是为了保证COW List本身的可见性,而是保证外部的非volatile变量的HB。

参考:
http://stackoverflow.com/questions/28772539/why-setarray-method-call-required-in-copyonwritearraylist
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics