【问题标题】:Vavr Set field should be volatile, atomic or declared other way?Vavr Set 字段应该是 volatile、atomic 还是以其他方式声明?
【发布时间】:2019-10-06 23:51:55
【问题描述】:

在 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&lt;Set&lt;String&gt;&gt; 吗?

【问题讨论】:

  • 用另一个替换不可变变量意味着您仍然具有可变状态。如果您有可变状态,则它不是一种功能方法。如果您不使用函数式方法,也许使用ConcurrentHashMap.newKeySet() 会更好?
  • 我喜欢函数式集合的地方在于,迭代器可以正常工作,而且您无需在传递之前克隆集合。

标签: java atomic volatile vavr


【解决方案1】:

我会使用AtomicReference。看到我的answer 来回答类似的问题。 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 另一方面保证变量是原子更新的。您必须将更新程序函数传递给AtomicReference,因此它将在以原子方式存储结果之前被调用。确保您使用的是没有副作用的纯函数,因为更新程序函数可能会被多次调用,以防引用同时被另一个线程原子更新。

【讨论】:

    猜你喜欢
    • 2019-08-07
    • 2014-02-12
    • 1970-01-01
    • 1970-01-01
    • 2018-07-29
    • 1970-01-01
    • 2021-03-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多