Vavr Set字段应该是volatile,atomic还是以其他方式声明?

时间:2019-05-20 15:17:43

标签: java atomic volatile vavr

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

我应该使用挥发物吗?我应该改用AtomicRef<Set<String>>吗?

1 个答案:

答案 0 :(得分:1)

我会使用AtomicReference。请参阅我的answer来回答类似的问题。波动性绝对是不够的,因为它仅保证对变量的更新将立即对其他线程可见(它有效地禁用了对其的缓存访问)。不过,并发线程访问将不会同步,因此可能发生两个线程同时构建更新的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,因此将在原子存储结果之前对其进行调用。确保您使用的是没有副作用的纯函数,因为如果同时另一个线程以原子方式对引用进行了更新,则可能会多次调用updater函数。