最终字段和线程安全

它是否应该是有目的不可变的java类’final’的所有字段,包括超级字段,以便是线程安全的,或者它是否足够没有修饰符方法?

假设我有一个非最终字段的POJO,其中所有字段都是某些不可变类的类型。 这个POJO有getter-setters,以及一个构造函数,它设置了一些初始值。 如果我使用敲除修饰符方法扩展此POJO,从而使其不可变,扩展类是否是线程安全的?

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

  • 从静态初始化程序初始化对象引用;
  • 将对它的引用存储到volatile字段或AtomicReference中;
  • 将对它的引用存储到正确构造的对象的最终字段中; 要么
  • 将对它的引用存储到由锁正确保护的字段中。

声明不可变对象的字段作为final释放此限制(即,它保证如果其他线程看到对该对象的引用,它们也会看到其完全初始化状态的final字段)。 但是,在一般情况下,它不保证其他线程一旦发布就可以看到对该对象的引用,因此您可能仍需要使用安全发布来确保它。

请注意,如果对象实现了接口,则可以使用Collections.unmodifiableList()等使用的方法:

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

是的,它将是不可变的,因此是线程安全的,但只要字段是私有的。