2

在 vavr 中,您拥有不可变的 io.vavr.collection.Set。考虑到addName()andnames()可以从各种线程中调用,使用它的正确方法和惯用方法是什么?

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;
  }
}

我应该使用易失性吗?我应该AtomicRef<Set<String>>改用吗?

4

1 回答 1

3

我会用AtomicReference. 请参阅我对类似问题的回答Volatile 绝对是不够的,因为它只保证对变量的更新将立即对其他线程可见(它有效地禁用了对它的缓存访问)。但是并发线程访问不会同步,因此可能会发生两个线程Set同时构建更新,并且其中一个线程将覆盖其他线程的更改。

给定两个同时运行的线程 T1 和 T2,想象以下事件序列:

  1. T1 读取变量,当前状态为 V
  2. T2 读取变量,当前状态为 V
  3. T1 计算更新状态 V×U1
  4. T2 计算更新状态 V×U2
  5. T1 将变量更新为 V×U1
  6. T2 将变量更新为 V×U2

上述序列的最终值将是 V×U2,因此更新 U1 实际上丢失了。

AtomicReference另一方面保证变量是原子更新的。您必须将 updater 函数传递给AtomicReference,因此它将在以原子方式存储结果之前被调用。确保您使用的是没有副作用的纯函数,因为更新程序函数可能会被多次调用,以防引用同时被另一个线程原子更新。

于 2019-05-21T00:11:13.963 回答