在 vavr 中,您拥有不可变的 io.vavr.collection.Set。
考虑到addName()
,使用它的正确方法和惯用方法是什么?和names()
可以从不同的线程调用吗?
import io.vavr.collection.Set;
import io.vavr.collection.HashSet;
public class Names{
public/*private*/ /**volatile*/ Set<String> names = HashSet.empty();
public void addName(String name){
names = names.add(name);
}
public Set<String> names(){
return names;
}
}
我应该使用 volatile 吗?我应该使用 AtomicRef<Set<String>>
相反?
最佳答案
我会使用AtomicReference
。看我的answer类似的问题。 volatile 肯定是不够的,因为它只能保证对变量的更新立即对其他线程可见(它有效地禁用了对其的缓存访问)。不过,并发线程访问不会同步,因此可能会发生两个线程同时构建更新的Set
,并且其中一个线程将覆盖其他线程更改的情况。
给定两个并发运行的线程 T1 和 T2,想象以下事件序列:
- T1读取变量,当前状态为V
- T2读取变量,当前状态为V
- T1计算更新状态V×U1
- T2计算更新状态V×U2
- T1 将变量更新为 V×U1
- T2 将变量更新为 V×U2
上述序列的最终值将是 V×U2,因此更新 U1 实际上会丢失。
另一方面,AtomicReference
保证变量以原子方式更新。您必须将更新器函数传递给 AtomicReference
,因此它将在原子存储结果之前被调用。确保您使用的是没有副作用的纯函数,因为如果同时另一个线程以原子方式更新引用,则更新器函数可能会被多次调用。
关于java - Vavr Set 字段应该是 volatile 的、原子性的还是以其他方式声明的?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56223825/