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
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章