手持ちのアプリで動作が少々怪しい部分があるのでどうすればその部分を排除できるかという観点に基づいて考えた結果、まずはここからかな?というところでインスタンスが万が一複数できてしまっていたらよくは無いと考え、検索してみてみました。
その中でこんな形のコードが出ていました。
package javatips;シングルトンパターンということで少々身構えしていたのですがよくある形のものです。
public class MySingleton {
// このクラスに唯一のインスタンス
private static MySingleton instance = new MySingleton();
private MySingleton() {}
// インスタンス取得メソッド
public static MySingleton getInstance() {
return instance;
}
// 以後、通常のフィールドやメソッドの宣言
...中略...
}
pascalであれば、ライブラリのコード中でも多用されていた形のものです。ユニットの初期化部分にインスタンスを作成したり、インスタンスを再作成できないようにカプセル化したり、javaと比べるとかなり言語依存しつつborlandによる拡張仕様によってなんとか実現させたものが数多く記憶にあります。
ただ上記のこのコードは、起動時にインスタンスを作成することを強要するので、使うか使わないか解らないものを起動時に初期化して用意するのは少々痛い気がします。
参照した中ではオリジナルのシングルトンパターンのコードや多重処理を考慮した形のコードも紹介されていました。
オリジナルのものは
GoFSingleton.javaで、turbo pascalのリファレンスマニュアルなどでよくあった形だと思います。
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;
}
// 以後、通常のフィールドやメソッドの宣言
...中略...
}
オリジナルのシングルトンパターンのコードであれば起動時に余計な処理は行われず、使用するときに始めてインスタンスの初期化処理が行われるのでとても合理的です。
ただし多重処理が行われる場合はインスタンスの生成時に排他的に行う必要が出てくるため、さらにそれを考慮した形のコードも紹介されていました。
GoFSingleton.javaに二重チェックを追加(抜粋)この場合はコード的に明らかに二重チェックになっていて処理的にも見た目的にもとても受け入れがたい形になっています。個人的に引用元となる解釈とは異なりますが、この二重チェックの最初のチェックを非同期で行うので、処理プロセス(日本語では通じる気がしますが英語だとなんのこっちゃ的な表現だな…単純に「処理」でいいのかな?)を考えるととても合理的に感じます。
public static GoFSingleton getInstance() {
if (instance == null) {
synchronized(GoFSingleton.class) {
// ここで再度チェックするため、「二重チェック」と呼ばれる
if (instance == null) {
instance = new GoFSingleton();
}
}
}
return instance;
}
ただ引用元で書かれている「Java仮想マシンの実装によっては、正しく動作しない問題が指摘されています。」 ということが本当だとすると、正直なところ仮想マシンのバグじゃないかって思います。具体的なVM名がわからないのでもやもやが残りますけど(笑)
参考クラスのインスタンスを1つに保つ(Singletonパターン)
0 件のコメント:
コメントを投稿