Singletonパターンを使ってクラスのインスタンスを1つにする(共有クラスのリソースを削減する方法)
マルチスレッド環境で共有リソースを使用するときに、各スレッドで同じオブジェクトを生成するとリソースの使用量が増えます。
またそのオブジェクトの初期化・生成にコストがかかるときには、同じ処理のために無駄なリソースを食うことになります。
このコストを削減するためには、インスタンスを使用する方法があります。
Singletonパターンを用いれば、構造上インスタンスを1つしか生成できないクラスを作成することができます。
Singletonパターンのポイントは、コンストラクタをprivateにして、インスタンスの取得に専用のstaticメソッドを用意することです。
Singletonパターンについては、デザインパターンをまとめたGang of Fourによる手法が有名です。
Gang of Fourとは
Erich Gamma、Richard Helm、Ralph Johnson、John Vlissidesの4人のことで、 デザインパターンをまとめた書籍『オブジェクト指向における再利用のためのデザインパターン』の著者です。
このコードは、マルチスレッド環境下でインスタンスが唯一であることを完全には保証できない、という問題が知られています。
public class GoFSingleton { private static GoFSingleton instance; private GoFSingleton() { // 最初はインスタンスを生成しない instance = null; } public static GoFSingleton getInstance() { // メソッド呼び出しがあったときに、初めてインスタンスを生成する if (instance == null) { // マルチスレッド環境下で、1つ目のスレッドがこの位置にいるときに、別のスレッドが上のif文の条件式を評価してしまうと、 // 2つ以上のスレッドがこのブロック内に入り込めてしまう instance = new GoFSingleton(); } return instance; } …………… ……… …………… }
getInstanceメソッドにsynchronized修飾子を付けることで、マルチスレッドの問題を回避することもできますが、メソッド呼び出しのたびに同期処理が行われるので、パフォーマンスが低下します。
同期処理のパフォーマンス低下を避けるために、次のような二重チェックをすることも考えられますが、この方法はJava仮想マシンの実装によっては、正しく動作しない問題が指摘されています。
public class GoFSingleton { private static GoFSingleton instance; private GoFSingleton() { // 最初はインスタンスを生成しない instance = null; } public static GoFSingleton getInstance() { if (instance == null) { synchronized(GoFSingleton.class) { // ここで再度チェックする if (instance == null) { instance = new GoFSingleton(); } } } return instance; } …………… ……… …………… }
インスタンスの存在チェックをせず、インスタンスの初期化時にインスタンスを生成する方法もあります。
クラスがJava仮想マシンへロードされたときに、一度だけインスタンスが生成され、唯一のインスタンスとしてprivateなstatic変数として保持されます。
これ以後、インスタンスの生成は構造上不可能になります。
public class MySingleton { // このクラスに唯一のインスタンス private static MySingleton instance = new MySingleton(); private MySingleton() {} // インスタンス取得メソッド public static MySingleton getInstance() { return instance; } …………… ……… …………… }
呼び出し元のコード
呼び出し側で、これらのインスタンスを取得するコードは次のようになります。
public static void main(String[] args) { GoFSingleton goFSingleton = GoFSingleton.getInstance(); }
ちなみにSingletonパターンではない場合は、次のようになると思いますので、ここを置き換えることになります。
public static void main(String[] args) { GoFSingleton goFSingleton = new GoFSingleton(); }
注意点
Singletonパターンは、容易に用いることができますが、使用には十分に注意する必要があります。
呼び出し元のクラス同士の依存関係が発生するからです。
次の条件を満たさない場合には使用するべきではないと思います。
クラスの初期化にコストがかかる場合
staticな値が、どの呼び出し元でも同じ値になる場合
関連記事
- 文字列の置き換えを行う方法 (replaceAllで気をつけること)
- 文字列の部分一致検索を行う方法
- Java メモリー使用量を取得する方法
- 実行中のメソッド名やクラス名を取得する方法
- ファイルのテキストデータを読み込む
- テキストデータをファイルに書き込む BufferedWriterの使用例
- Webからダウンロードして保存する DefaultHttpClientの使用例
- ファイルをコピーする InputStream,OutputStreamの使用例
- 暗号化・複合化を行う ブロック暗号
- base64変換の一覧とその詳細サンプルコード
- 型変換の一覧(キャスト)
- 処理を一定時間停止させる方法
- ファイルの拡張子を取得する
- Java
- サンプルコード
- Androidアプリ
- 2.0/2.1以前で再生できる動画が2.2以降で再生できない
- SDカードが接続されているかどうか知る方法 書き込み可能かどうか 読み込み可能かどうか
- EclipseでAndroidプロジェクトを作る方法
- アプリからネットワーク通信を行う場合
- Mobile Network Code(MNC)の一覧[T-U]
- ターミナルで端末操作をする方法
- Mobile Network Code(MNC)の一覧[S]
- リソースファイルの設置場所と利用方法
- 画面UIパーツのclass一覧
- Mobile Network Code(MNC)の一覧[O-R]
- apkファイルをサーバから端末にダウンロードする
- facebook APIを使用する時にfacebook Appsでアプリを登録するまでの流れ
- アプリケーションプロセスを強制的に終了する方法
- cron実行時に『/bin/sh: 〜〜: command not found』と出てcronが実行されない場合
- テーマ機能を使ってアプリケーション全体にスタイルを適用させる方法
- WebViewを使ってWebサイトを表示する方法 WebKitからアプリ、アプリからWebKitへの連携処理
- Mobile Network Code(MNC)の一覧[E-G]
スポンサーリンク