Vavr Set 字段应该是 volatile、atomic 还是以其他方式声明?
Vavr Set field should be volatile, atomic or declared other way?
在 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
。请参阅我的 类似问题。 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
,以便在以原子方式存储结果之前调用它。确保您使用的是没有副作用的纯函数,因为更新函数可能会被调用多次,以防引用同时被另一个线程自动更新。
在 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
。请参阅我的 Set
,并且其中一个线程将覆盖其他线程更改。
给定两个 运行 并发的线程 T1 和 T2,想象以下事件序列:
- T1读取变量,当前状态为V
- T2读取变量,当前状态为V
- T1计算更新状态V×U1
- T2计算更新状态V×U2
- T1更新变量为V×U1
- T2更新变量为V×U2
上述序列的最终值为V×U2,因此更新U1实际上丢失了。
另一方面,AtomicReference
保证变量以原子方式更新。您必须将更新程序函数传递给 AtomicReference
,以便在以原子方式存储结果之前调用它。确保您使用的是没有副作用的纯函数,因为更新函数可能会被调用多次,以防引用同时被另一个线程自动更新。