Java 最终字段和线程安全

Java 最终字段和线程安全,java,thread-safety,immutability,Java,Thread Safety,Immutability,为了线程安全,它应该是故意不可变的java类“final”的所有字段(包括超级字段),还是没有修饰符方法就足够了 假设我有一个具有非final字段的POJO,其中所有字段都是某个不可变类的类型。这个POJO有getters setter和一个设置一些初始值的构造函数。如果我用剔除修饰符方法扩展这个POJO,从而使它不可变,扩展类是线程安全的吗?为了以线程安全的方式使用一个没有final字段的有效不可变对象,在初始化后使对象对其他线程可用时,您需要使用一种安全发布习惯用法,否则这些线程可以看到对象

为了线程安全,它应该是故意不可变的java类“final”的所有字段(包括超级字段),还是没有修饰符方法就足够了


假设我有一个具有非final字段的POJO,其中所有字段都是某个不可变类的类型。这个POJO有getters setter和一个设置一些初始值的构造函数。如果我用剔除修饰符方法扩展这个POJO,从而使它不可变,扩展类是线程安全的吗?

为了以线程安全的方式使用一个没有
final
字段的有效不可变对象,在初始化后使对象对其他线程可用时,您需要使用一种安全发布习惯用法,否则这些线程可以看到对象处于部分初始化状态(从):

  • 从静态初始值设定项初始化对象引用
  • 将对它的引用存储到易失性字段或原子引用中
  • 将对它的引用存储到正确构造的对象的最终字段中;或
  • 将对它的引用存储到由锁正确保护的字段中
将不可变对象的字段声明为
final
将释放此限制(即,它保证如果其他线程看到对该对象的引用,它们也会看到其
final
字段处于完全初始化状态)。但是,在一般情况下,它不能保证其他线程在对象发布后就可以看到该对象的引用,因此您可能仍然需要使用安全发布来确保它

请注意,如果您的对象实现了一个接口,则可以使用
集合使用的方法。不可修改列表()
等:

class ImmutableFooWrapper implements IFoo {
    private final IFoo delegate; // final provides safe publication automatically

    public ImmutableFooWrapper(IFoo delegate) {
        this.delegate = delegate;
    }
    ...
}

public IFoo immutableFoo(IFoo foo) {
    return new ImmutableFooWrapper(foo);
}

是的,它是不可变的,因此是线程安全的,但前提是字段是私有的。

删除修饰符方法是什么意思?从所有setter引发异常?这将违反法律。是的,这个类是线程安全的。是的,抛出一个运行时异常或者用一个空的主体重写它们,可能需要一些日志记录。我知道这违反了LSP。谢谢你详细的回答。我曾经考虑过使用委托的相同解决方案,但后来我总是返回到带有扩展的解决方案,因为我猜“super”引用也是最终的。我错过了什么?@pcjuzer:
super
与并发无关,因此在扩展的情况下,无论如何都需要安全发布。所以,这意味着,如果您正在声明一个字段final,那么如果它正在由一个线程更新,那么另一个线程将不会看到它,如果它看到,那么它将在更新状态下看到它?为什么字段实际上必须是私有的?