2011-08-22 6 views
6

スレッドセーフであるためにスーパーイントルを含むすべてのフィールドが意図的に変更不能なJavaクラス「final」でなければなりませんか、それとも修飾メソッドを持たないのでしょうか?最終フィールドとスレッドセーフ

すべてのフィールドが不変なクラスの型である非最終フィールドのPOJOがあるとします。このPOJOにはgetters-settersがあり、初期値を設定するコンストラクタがあります。このPOJOを修飾子メソッドをノックアウトして拡張すると、それを不変にすると、拡張クラスはスレッドセーフになりますか?

+2

修飾子メソッド*修飾子メソッドをノックアウトするとどういう意味ですか?すべてのセッターから例外をスローしますか?これは[Liskov置換原則](http://en.wikipedia.org/wiki/Liskov_substitution_principle)に違反します。しかし、はい、このクラス**はスレッドセーフです**。 –

+0

はい、ランタイム例外をスローするか、空のボディでオーバーライドしている可能性があります。私はそれがLSPに違反していることを知っています。 – pcjuzer

答えて

11

finalフィールドを含まない効果的な不変オブジェクトをスレッドセーフな方法で使用するには、オブジェクトを初期化後に他のスレッドが使用できるようにするときに安全な公開慣用法の1つを使用する必要があります。 (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); 
} 
+0

詳細な回答ありがとうございます。私はデリゲートを使って同じソリューションについて考えていましたが、私は「スーパー」リファレンスも最終的だと思っていたので、私はいつも拡張機能を使ってソリューションに戻りました。何が欠けていますか? – pcjuzer

+0

@pcjuzer: 'super'は並行処理とは関係がないので、拡張の場合は、とにかく安全な公開が必要です。 – axtavt

+0

これは、フィールドが最終的に宣言されている場合に、あるスレッドによって更新されていて、他のスレッドはそれを表示せず、表示されていれば更新された状態で表示されることを意味します。 – AKS

-2

はい、それだけで限り、フィールドがあるとして不変、その結果、スレッドセーフではなくなりますプライベート。

+2

フィールドが実際にプライベートである必要があるのはなぜですか? – xSNRG

関連する問題