最终字段和线程安全

时间:2011-08-22 08:39:57

标签: java thread-safety immutability

为了是线程安全的还是没有修饰符方法,它应该是有目的不可变的java类'final'的所有字段,包括超级字段吗?

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

2 个答案:

答案 0 :(得分:14)

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

  
      
  • 从静态初始化程序初始化对象引用;
  •   
  • 将对它的引用存储到易失性字段或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);
}

答案 1 :(得分:-3)

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