
在 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 属性被写了,后续对他们的读操作的可见性就有了保证。 |