小编典典

最终字段和线程安全

java

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

假设我有一个带有非最终字段的POJO,其中所有字段都是某种不可变类的类型。这个POJO有getters-
setters和一个设置一些初始值的构造函数。如果我通过敲除修饰符方法来扩展此POJO,从而使其不可变,那么扩展类是否是线程安全的?


阅读 210

收藏
2020-11-01

共1个答案

小编典典

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

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

将不可变对象的字段声明为as
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);
}
2020-11-01