在实例重新分配期间锁定变量

Locking a variable during instance reassignment

假设我有两个线程:Thread-AThread-B

Thread-A 计划更新其 class:

中的局部变量
public class SomeClass {

    private List<String> aSpecialList = new ArrayList<>();

    @Scheduled(....)
    public void updateASpecialList() {
        List<String> aBetterSpecialList = new ArrayList<>()

        // all these great things happen to aBetterSpecialList
        ...

        aSpecialList = aBetterSpecialList;
    }

    public List<String> getASpecialList() {
        return aSpecialList;
    }
}

现在,Thread-BThread-A 即将执行变量重新分配时尝试访问此列表 (SomeClass::getASpecialList())。如果我不锁定 aSpecialList?

是否有可能导致任何形式的并发问题

既然aSpecialList是不可变的,那么aSpecialList = aBetterSpecialList就是an unsafe publication
因此,当 Thread-B 读取 aSpecialList.
时,我们不会得到所谓的 happen-before 关系(来自 JMM 的术语) 结果我们遇到了以下并发问题(也称为数据竞争):

  1. Thread-BaSpecialList 的读取是活泼的:每次独立读取都可能 return 在整个生命周期内任何其他线程写入该字段的任何值程序
  2. Thread-B 对存储在 aSpecialList 中的 ArrayList 中的任何字段的任何读取也是活泼的。
    例如,Thread-B 可以看到 size of the ArrayList and its internalelementData 数组的值不一致。

其中一个解决方案是使 aSpecialList 易变,然后:

  • Thread-B 保证可以看到 Thread-A
  • aSpecialList 的写入
  • Thread-B 也保证可以看到 ArrayList 存储在 aSpecialList 中的内部状态,就像它在发布时一样

另外我也会把你写的列表写成aSpecialList immutable.