在 CopyOnWriteArrayList 类的 set 方法中有一段 setArray(elements)代码,实际上这段代码并未对 elements 做任何改动,实现的 volatile 语意并不对 CopyOnWriteArrayList 实例产生任何影响,为什么还是要保留这行语句?
public E set(int index, E element) {
final ReentrantLock lock = this.lock;
lock.lock();
try {
Object[] elements = getArray();
E oldValue = get(elements, index);
if (oldValue != element) {
int len = elements.length;
Object[] newElements = Arrays.copyOf(elements, len);
newElements[index] = element;
setArray(newElements);
} else {
//就是这里
// Not quite a no-op; ensures volatile write semantics
setArray(elements);
}
return oldValue;
} finally {
lock.unlock();
}
}
1
BBCCBB 2020-06-27 11:00:02 +08:00
你百度一下很多讲这个得, 为了保证 volatile 得语义, 就是 happens before 规则里定义的..
|
2
BBCCBB 2020-06-27 11:01:56 +08:00
有一个概念叫 `捎带同步`
|
3
seaswalker 2020-06-27 12:29:14 +08:00
|
4
bigbyto 2020-06-27 12:45:45 +08:00
简单来说就是保证 happens before 原则。jls 中 happens before 中有一条是
A write to a volatile field (§8.3.1.4) happens-before every subsequent read of that field. 对一个 volatile 变量的写入操作 happens before 其他线程对它的读操作。 |
5
ky11223344 2020-06-27 12:58:47 +08:00
应该是为了保证 set 方法之前的所有写操作能够被后续的读操作可见吧,volatile 规定了是这样的。不然可能来一个 set,element 参数和 oldValue 一样,然后没有 setArray 把所有该线程执行过的写操作刷到主内存,后续读就可能读不到 set 之前的所有写过的值了,这些值可能是同一个 object 里的属性,是多个线程的共享变量,可以是 volatile 也可以不是的,但只要他们之后有一个 volatile 属性被写了,后续对他们的读操作的可见性就有了保证。
|