为了线程安全,是否应该是故意不可变的Java类’final’的所有字段(包括超字段),还是没有修饰符方法就足够了?
假设我有一个带有非最终字段的POJO,其中所有字段都是某种不可变类的类型。这个POJO有getters- setters和一个设置一些初始值的构造函数。如果我通过敲除修饰符方法来扩展此POJO,从而使其不可变,那么扩展类是否是线程安全的?
为了以final线程安全的方式使用没有字段的有效不可变对象,在初始化后使对象可用于其他线程时,需要使用一种安全的发布习惯用法,否则这些线程可以看到处于部分初始化状态的对象(来自Java并发在实践中):
final
从静态初始化程序初始化对象引用; 将对它的引用存储到volatile字段或AtomicReference中; 将对它的引用存储到适当构造的对象的最终字段中;要么 将对它的引用存储到由锁适当保护的字段中。
将不可变对象的字段声明为as final会释放此限制(即,如果其他线程看到对该对象的引用,它们也final将以完全初始化的状态看到其字段)。但是,通常情况下,它不能保证其他线程可以在对象发布后立即看到对该对象的引用,因此您可能仍需要使用安全发布来确保对该对象的引用。
请注意,如果您的对象实现了接口,则可以使用Collections.unmodifiableList(),等使用的方法:
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); }