インスタンスの生成を制限する。
使い道は主にGofのデザインパターンのSingletonで良く使われるイディオムです。
また、マルチスレッドでインスタンスの生成を制限する場合も効果的です。
double-checked lockingイディオム
残念ながらJavaではアウトオブオーダーと呼ばれるメモリ制御をしているため実現できません。(通りすがりさんに感謝)
コーディング上は一見実現できそうですが、アウトオブオーダーによって作業メモリから復帰させるタイミングで割り込みが発生した場合、インスタンスが二つ生成される現象があります。
実際のJavaのコーディング例です。
(Javaでは実現できませんが、こんな方法があると言うコトくらい覚えておいて損は無いかも。)
1| public static XxxxxConfig getInstance() { 2| // double-checked lockingイディオム(実際には動作は約束されません。) 3| if (instance == null) { 4| synchronized (XxxxxConfig.class) { 5| if (instance == null) { 6| instance = new XxxxxConfig(); 7| } 8| } 9| } 10| return instance; 11| }
このイディオムの核心は3行目と4行目です。
まず、3行目のif文でインスタンスをチェックして無い場合はインスタンスを生成するようにします。
次に、4行目のsynchronizedブロックで自身のクラス変数classをロック対象にして他のスレッドから
同時に操作を行わないようにします。
5行目は奇妙に思えるかもしれませんが、ロックしたばかりだと直前で割り込まれる可能性があるために
再度チェックしてインスタンス生成を行います。
staticなインナークラスの利用
早速、通りすがりさんのお陰で解決です。
とりあえず、忘れないように核心部分の説明をします。
1|public class XYZ { 2| 3| private static class Instance { 4| static final XYZ instance = new XYZ(); 5| } 6| 7| private XYZ() { 8| } 9| 10| public static XYZ getInstance() { 11| return Instance.instance; 12| } 13| 14|}
先に核心部分を言うと3〜5行目と10〜12行目です。
- 1
- まず3行目のインナークラスです。このクラスはstaticなクラスとして定義されているので最初にクラス参照が行われると呼び出されます。
- 2
- 続いて4行目、staticとfinalという修飾で「変更無しの唯一のインスタンス」が生成されます。
- 3
- 10行目のメソッドを呼び出すコトでインナークラスの「変更無しの唯一のインスタンス」が返されます。
このコードを見た限りでは以下の点に優れています。
- スレッドセーフなSingleton
- アウトオブオーダーが原因による初期化の2重呼び出し対策
これでほぼ完璧です。気になることと言えばクラスローダー毎にSingletonのインスタンスが生成されます。
ま、それでもSingletonがクラスローダーに跨るならばLDAPを利用したJNDIとか使えばイケそうな気がします。(面倒でやりたくないですが。)
とりあえず、JavaでSingletonの実現はこんな感じで。
コレよりも良い方法や問題点があればコメントをお願いします。