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 了。
各位大佬,上面这两种情况,我想得对吗?
1
orangex 2020-05-10 17:29:02 +08:00
应该只有前者吧。
1. return 语句里前面几个逻辑运算是不是原子操作呢?我也不清楚,如果是的话,那就不存在你说的切出去的情况。 2. 就算是别的线程修改了,stamp 这里应该类似版本号的作用吧?这个“戳”只应该越改越大吧 |
2
amiwrong123 OP @orangex
理论上版本号应该越来越大,但这里提供的函数,就是随便设置版本号。 我也感觉后者不成立。因为 current 只是一个局部变量,就算线程切出去又切回来,此时 current 就变成了一个孤儿了(只有 current 局部引用指向它),假设其他线程 趁你切出去更新了 pair 对象。此时,pair 成员一定是新的 pair 对象。此时,再通过 casPair 判断,发现 current 局部变量就不是旧引用了。 |