使用不可变Java记录Record来避免多线程并发错误 - foojay


在多线程 Java 应用程序中,任何线程都可以更改对象的状态。Java 语言规范中的Java 内存模型指定了一个线程所做的准确更新何时对其他线程可见。这是专业 Java 开发人员每天处理的最大问题之一。Java 记录record是不可变的,如果对象在构造后其状态不能改变,则该对象被认为是不可变的。记录的不可变特性消除了它在多线程环境中使用的问题。
记录组件是最终的,这意味着我们不能更改分配后的记录组件。虽然我们可以改变记录组件的字段,但没有限制,它使记录浅不可变。让我们用一个例子来看看。

public class EmployeeTest {

    public static void main(String[] args) {

        List<Integer> integerList = new ArrayList<>();
        integerList.add(1);
        IntegerListRecord integerListRecord = new IntegerListRecord(integerList);
        System.out.println(integerListRecord.getListSize());

        integerList.add(2);
        System.out.println(integerListRecord.getListSize());

    }

}

record IntegerListRecord(List<Integer> integerList) {
    int getListSize() {
        return integerList.size();
    }
}

在这个例子中,我们创建了一个整数列表(integerList),向其中添加了一个元素,并用它初始化了记录类。调用record类的getListSize方法结果为1。现在我们在integerList中再增加一个元素,调用getListSize结果为2。这里我们没有改变record组件(integerList)而是更新了record组件的字段,它没有任何限制。这就是我们称记录为浅不可变的原因。
 
记录Record不可变特点:

  • 记录类是隐式最终的,不能是抽象的,这样我们就不能创建记录类的子类。
  • 所有记录类默认扩展 java.lang.Record 所以不能扩展任何其他类。
  • 记录类不能声明实例字段。
  • 我们不能为记录组件分配一个新值,因为它们是隐式最终的。这些是在规范构造函数中初始化记录时分配的值。
  • 只有规范构造函数可以更新记录组件,在初始化记录时调用。对于其他类型的构造函数,在构造函数主体中分配任何记录组件都会导致编译时错误。
  • 记录组件在反射中有特定的处理 字段API. 这种处理就像隐藏类。您可以阅读有关隐藏课程的更多信息这里.

 
结论
记录可帮助您删除重复且容易出错的代码,并提高开发人员的工作效率。不变性功能使其远离并发错误。使用这样的语言功能将使您成为每个人都想雇用的优秀开发人员。