Skip to content

Instantly share code, notes, and snippets.

@YuyaAizawa
Created May 17, 2018 13:07
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save YuyaAizawa/ab4c1513ef1f73c40b401884fa727511 to your computer and use it in GitHub Desktop.
Save YuyaAizawa/ab4c1513ef1f73c40b401884fa727511 to your computer and use it in GitHub Desktop.
JavaにおけるSingletonの実装

Singleton シングルトン

あるクラスのインスタンスが1つしか存在しないようにして,また外部からアクセスできるようにする.

インスタンスを複数生成させないために留意すべき点は以下の通り

  • newさせない
    • コンストラクタはprivateに
    • インスタンスはファクトリメソッドなどを利用して取得
    • 遅延初期化したい
      • 複数スレッドからのアクセスを想定
  • デシリアライズさせない
    • readResolveを利用
  • クローンさせない

以上を守れば普通は問題ないが,よりセキュアにするために以下のような観点もあるようだ

  • GCに回収させない(他のClassLoaderを利用させない)
  • リフレクションで作成させない

がんばって(そしてテクニカルに)実装する

間違えやすいので後述のenumを使ったほうが良い.

この例は機能をテンコ盛りだが,必要な部分だけ実装すればOK

class Singleton extends CloneableClass implements Serializable {

	// フィールドは全てtransientに
	private transient String field;

	// 外部のクラスからコンストラクタにアクセスさせない
	private Singleton() {
		// 初期化
	}

	// Initialize-on-Demand Holderパターンによる遅延初期化クラス
	private static class SingletonHolder {
		static Singleton singleton = new Singleton();

		Singleton getInstance() {
			return singleton;
		}
	}

	// ファクトリメソッド
	public static Singleton getInstance() {
		return SingletonHolder.getInstance();
	}

	// デシリアライズの結果を上書き
	private Object readResolve() throws ObjectStreamException {
		return getInstance();
	}

	// クローンさせない
	public Object clone() throws CloneNotSupportedException {
		throw new CloneNotSupportedException();
	}
}

enumを利用

enumを利用すると(特にserialize周りで)面倒なことをVMに任せられる

enum Singleton { // enumは既にSerializable
	INSTANCE;

	// transientにしなくてよい
	private String field;
}

ただし,この方法はインターフェースは実装できるがクラスを継承できない

Double-checked lockingの話はやめよう

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment