次のSpringServiceクラスについて考えてみます。定義されているスプリングスコープはシングルトンです。以下のクラスのフィールドとして自動配線された2つのサービスBeanは、同様の構造を持っています。これらも、次のいずれかのフィールドで構成されています。
等々。このパターンは、アプリケーション設計で全体的に使用されます。
@Service
public class DocumentService {
private final DocumentGenerationService documentGenerationService;
private final DocumentPublishService documentPublishService;
@Autowired
public DocumentService (DocumentGenerationService documentGenerationService,
DocumentPublishService documentPublishService) {
this.documentGenerationService = documentGenerationService;
this.documentPublishService = documentPublishService;
}
... methods follow
DocumentServiceクラスは、その2つのフィールド(コンテナー自体によって一度だけ初期化できるSpring Bean)のいずれも変更できないため、不変であると言うのは正しいですか?
いずれにせよ、上記で定義されたDocumentService Beanはスレッドセーフと見なすことができますか?そして、この設計がアプリケーション全体に準拠している場合、スレッドセーフでもありますか?
DocumentServiceクラスは2つのフィールド(コンテナ自体で一度だけ初期化できるSpring Bean)のいずれも変更できないため、不変であると言うのは正しいですか?
不変性の定義 によると、正式に言えば、このクラスは不変ではないです。
オブジェクトの状態を変更できない場合、オブジェクトは不変であり、documentGenerationService
およびdocumentPublishService
はクラスの状態の一部ですDocumentService
。
そして、その結果、クラスがalways同じ状態の場合、always同じように動作します。言い換えると、オブジェクトの動作はその状態にのみ依存し、不変のオブジェクトではこの状態は決して変化しないため、不変のオブジェクトの動作を変更する方法はありません(不変のオブジェクトの例は文字列と整数です)。
不変性の定義では、「一部の[...]属性が変更されても、オブジェクトの状態 [したがって、動作]が変更されても、オブジェクトは不変と見なされるという例外があります。 変更されていないように見えます[...] "ですが、この場合(提供された情報を使用して)、参照の状態を変更すると、クラスの動作が確実に変更される可能性があります(自身の内部状態を制御することはできません)。
クラスを不変にするためのstrategyがあります。あなたはすでにそのガイドラインのいくつかに従っていますが、それを不変にしたい場合(そうではないと思います)、受け取る引数のmake "defensive copy"のような他のものが必要になりますコンストラクターでメソッドをオーバーライドするサブクラスを回避する。
この リンク も面白いです。
それでも、Springが提供するプログラミングモデルを使用する方法ではないため、 Spring Beanを不変にしないでください。したがって、この場合、クラスが不変でないことは「良い」ことです。
いずれにせよ、上記で定義されたDocumentService Beanはスレッドセーフと見なすことができますか?
ここで宣言されているように、このクラスISスレッドセーフ。多くのスレッドは、競合状態が発生することなく、このクラスに安全にアクセスできます。含まれているフィールドについて同じことを言うことはできませんが、このクラスはスレッドセーフです。これは「スレッドセーフリスト」とまったく同じように機能します。「スレッドセーフなし」オブジェクトを含めることができますが、それでも「スレッドセーフリスト」のままです。
そして、この設計に従っている場合、アプリケーション全体もスレッドセーフですか?
システムのすべてのクラスがスレッドセーフである場合(つまり、単一の競合状態がどこにも表示されない場合)、非公式にアプリケーションがスレッドセーフであると言うことができます。
Springはスレッドセーフを保証しません。それはあなたの責任です。
すべてのプライベートメンバー変数が共有されます。それらは最終的なものかもしれませんが、それは参照を変更できないことを意味するだけです。可変状態はすべて同期する必要があります。それらが実際に不変である場合、私はあなたが堅実な立場にいると思います。
自動配線の依存関係についてのコメントに同意します。可能であれば、Springの管理下に置いておきます。
あなたの質問に示されているサンプルコードは間違いなくスレッドセーフです。
ただし、コードはアプリケーション全体のコンテキストで検討する必要があります。たとえば、上記のコードは、documentGenerationService
属性とdocumentPublishService
属性によって参照されるオブジェクトのスレッドセーフについての保証を提供しません。それらが適切に同期されていない場合、それらを使用するコード(このクラスの他のメソッドを含む)はスレッドセーフではない可能性があります。
コンストラクターで使用する代わりに、サービスの上に@Autowiredアノテーションを配置できます。これはSpringマネージドBeanであり、シングルトンであることを意味します。スレッドセーフですが、それは実装によって異なります。
@Service
public class DocumentService {
@Autowired
private DocumentGenerationService documentGenerationService;
@Autowired
private DocumentPublishService documentPublishService;
... methods follow
コードはスレッドセーフに見えます。 Springは、Beanがシングルトンであると言っている場合、スレッドセーフを保証しません。 SpringでシングルトンスコープのBeanを作成する場合、それは単にSpringIoCコンテナごとに単一のオブジェクトインスタンスが作成されることを意味します。しかし、それでも、そのシングルトンスコープのBeanクラスは、それ自体がスレッドセーフではない可能性があるため、コードをスレッドセーフにするプログラマーの責任があります。
あなたのコードでは、例えばdocumentGenerationService
はfinalです。これにより、参照が変更されないことが保証され、新しいJavaメモリモデルから、インスタンス化が保証されます。ただし、@ duffymoによると、参照されるオブジェクトも不変である必要があります。
残りはすべて良いです:)
Springは、Beanがシングルトンであると言っている場合、スレッドセーフを保証しません。 SpringでシングルトンスコープのBeanを作成する場合、それは単にSpringIoCコンテナごとに単一のオブジェクトインスタンスが作成されることを意味します。しかし、それでも、そのシングルトンスコープのBeanクラスは、それ自体がスレッドセーフではない可能性があるため、コードをスレッドセーフにするプログラマーの責任があります。