Javaの高度な単例の合理的な使い方

2032 ワード


                                       この文書はhttp://blog.csdn.net/liuxian13183/ ,引用は出典を明記しなければならない!
単一の例では、「クラス」の参照を共有し、内部業務を操作することを目的としています.したがって、単一の例は、マルチスレッドに使用されるべきである.
単一スレッドの場合は、メンバー変数としてクラスを直接使用して内部ビジネスを操作することをお勧めします.
利点:クラスオブジェクトを複数回初期化する必要がなく、クラスの参照を共有します.
劣勢:使用が完了したら、「単一例/その内部メンバー変数」を空にする必要があります.静的であるため、デフォルトでは内部メンバー変数はGCで回収されません.
よくある書き方は3種類あります.
餓漢式
public static class HungrySingleInstance {
		private static final HungrySingleInstance instance = new HungrySingleInstance();

		private HungrySingleInstance() {
		}

		public static HungrySingleInstance getInstance() {
			return instance;
		}
	}

クラスがgetInstanceメソッドを呼び出すと、初期化操作が実行されます.
せいてきしき
	public static class HolderSingleInstance {

		private HolderSingleInstance() {
		}

		private static class SingleHolder {
			private static final HolderSingleInstance instance = new HolderSingleInstance();
		}

		public static HolderSingleInstance getInstance() {
			return SingleHolder.instance;
		}
	}

上記と同様に、上記のクラスが他のメソッドを呼び出すとinstanceも初期化され、「メモリを事前に占有しているが、使用しない」という疑いがあります!次のクラスでは、getInstanceメソッドを呼び出すだけで、単一のオブジェクトが取得されます.
怠け者風
	public static class LazySingleInstance {
		private static volatile LazySingleInstance instance;

		private LazySingleInstance() {
		}

		public static LazySingleInstance getInstance() {
			if (instance == null) {
				synchronized (LazySingleInstance.class) {
					if (instance == null) {
						instance = new LazySingleInstance();
					}
				}
			}
			return instance;
		}
	}

getInstanceが実行されると、初期化されます.ロックは、2つのスレッドが同時に入ることを保証するために、一度だけ初期化し、初期化後のオブジェクトを取得します.
メソッド内にロックを追加するのは、複数のスレッドを保証するために、メソッド領域ハンドルで待つのではなく、メソッド内部で待つためであり、より効率的です.volatileはここで、仮想マシン階層のみからインスタンスがコピーされないことを保証し、実際の意味は大きくありません.
 
問題1:静的変数は破棄されず、内部メンバー変数を保持しているため、ページレベルのメモリが漏洩しやすい.
問題2、単例内の非静的メンバー変数は、弱い参照パッケージを使用するか、空にして回収を保証することができる.一方、静的変数は、参照を弱くしてもアクティブGCによって回収されません.静的変数であるためです.
 
メモリの詳細については、移行可能:Java高度なメモリ初期化タイミング