歴史的に、遅延初期化はリソースの使用を最適化するために登場しました。これは、オブジェクトが本当に必要なときにのみ作成されるときに起こります。最初は、重いオブジェクトや接続、キャッシュ、または複雑なパターン(たとえば、シングルトン)を扱う際に重要でした。
問題は、すべてのリソースをすぐに作成すると、オブジェクトが不要な場合でも余分なメモリ、時間、パワーを消費してしまう可能性があることです。遅延初期化は「遅延作成」の問題を解決します。
解決策は通常、チェックによって実装されます。オブジェクトがまだ作成されていない場合は、それを作成し、そうでない場合は既存のものを返します。
コード例:
public class LazyHolder { private Resource resource; public Resource getResource() { if (resource == null) { resource = new Resource(); } return resource; } }
マルチスレッド環境では、同期が必要です。
主な特徴:
ダブルチェックロッキングはシングルトンの遅延初期化に信頼できる実装ですか?
Java 5以降のみ、以前はメモリモデルがこれを保証していませんでした。リソースフィールドにはvolatileキーワードを使用する必要があります。
private volatile Resource resource; public Resource getResource() { if (resource == null) { synchronized(this) { if (resource == null) { resource = new Resource(); } } } return resource; }
軽量オブジェクトに対して遅延初期化を行う意味はありますか?
一般的には、ありません。「軽量」オブジェクトをすぐに作成した方が、コードの可読性を損なわず、余分なロジックで複雑化させることがありません。
オブジェクトのシリアライズ時に遅延初期化は機能しますか?
必ずしもそうではありません。シリアライズ時に「古い」状態が復元されたり、readObject()に追加のロジックが必要になる場合があります。
高負荷サービスでは、特別なオブジェクトプールが遅延でパースされましたが、同期されていませんでした。二つのスレッドが同時にオブジェクトを初期化し、メモリリークや予測できないエラーを引き起こしました。
長所:
短所:
大規模なウェブアプリケーションでは、分析が遅延初期化されたプロキシオブジェクトを介してAPI呼び出しにのみ接続されます。
長所:
短所: