CopyOnWriteArrayList 类 set 方法疑惑

2020-06-27 10:55:17 +08:00
 amiwrong123

在 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();
        }
    }
2067 次点击
所在节点    Java
5 条回复
BBCCBB
2020-06-27 11:00:02 +08:00
你百度一下很多讲这个得, 为了保证 volatile 得语义, 就是 happens before 规则里定义的..
BBCCBB
2020-06-27 11:01:56 +08:00
有一个概念叫 `捎带同步`
seaswalker
2020-06-27 12:29:14 +08:00
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 其他线程对它的读操作。
ky11223344
2020-06-27 12:58:47 +08:00
应该是为了保证 set 方法之前的所有写操作能够被后续的读操作可见吧,volatile 规定了是这样的。不然可能来一个 set,element 参数和 oldValue 一样,然后没有 setArray 把所有该线程执行过的写操作刷到主内存,后续读就可能读不到 set 之前的所有写过的值了,这些值可能是同一个 object 里的属性,是多个线程的共享变量,可以是 volatile 也可以不是的,但只要他们之后有一个 volatile 属性被写了,后续对他们的读操作的可见性就有了保证。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/684994

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX