AtomicStampedReference 的 CAS 操作,这么理解对吗

2020-05-10 17:08:14 +08:00
 amiwrong123
    public boolean compareAndSet(V   expectedReference,
                                 V   newReference,
                                 int expectedStamp,
                                 int newStamp) {
        Pair<V> current = pair;
        return
            //旧引用是相同的
            expectedReference == current.reference &&
            //旧版本号也是相同的
            expectedStamp == current.stamp &&
            //想设的新引用和新版本号,也和当前的相同
            ((newReference == current.reference && newStamp == current.stamp) ||
             casPair(current, Pair.of(newReference, newStamp)));
    }

就是上面的((newReference == current.reference && newStamp == current.stamp) ||这里,首先我觉得,可能调用这个函数的时候,参数 expectedReference 就是 newReference 一样的,同样,expectedStamp 和 newStamp 也一样的。但是这样做 CAS 操作,不就相当于没有进行设置吗,反正都是一样的。

然后,我又想到,难道这里还有另一种情况。调用这个函数时,参数 expectedReference 和 newReference 是不一样的,expectedStamp 和 newStamp 也不一样的。但线程执行到expectedStamp == current.stamp就切换出去了,然后切换回来了,current 的两个成员刚刚被别的线程修改了,然后刚好通过了(newReference == current.reference && newStamp == current.stamp)的判断,也就不用执行 casPair 了。

各位大佬,上面这两种情况,我想得对吗?

1207 次点击
所在节点    Java
2 条回复
orangex
2020-05-10 17:29:02 +08:00
应该只有前者吧。
1. return 语句里前面几个逻辑运算是不是原子操作呢?我也不清楚,如果是的话,那就不存在你说的切出去的情况。
2. 就算是别的线程修改了,stamp 这里应该类似版本号的作用吧?这个“戳”只应该越改越大吧
amiwrong123
2020-05-10 17:50:02 +08:00
@orangex
理论上版本号应该越来越大,但这里提供的函数,就是随便设置版本号。

我也感觉后者不成立。因为 current 只是一个局部变量,就算线程切出去又切回来,此时 current 就变成了一个孤儿了(只有 current 局部引用指向它),假设其他线程 趁你切出去更新了 pair 对象。此时,pair 成员一定是新的 pair 对象。此时,再通过 casPair 判断,发现 current 局部变量就不是旧引用了。

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

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

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

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

© 2021 V2EX