Pocket

HeadFirstデザインパターン5章 は、Singletonパターンです。(架空の会社)Choc-O-Holic社の業務用チョコレートボイラを扱うためのコントローラクラスに、同期化していないSingletonを実装しました。

ところがマルチスレッドを導入したために、ボイラーが大変なことに!

マルチスレッドに対応するために、synchronizedバージョン、クラスロード時インスタンス化バージョン、ダブルチェックドロッキングバージョンを作っていきます。

githubの書籍サンプルコード/singleton

書籍のサンプルコードとは別に、1000スレッドを起動して、Singletonかどうかを確認するmainを作りました。

Main.java最初のバージョン

異なるインスタンスが何個生成されるか、HashMapで集計しました。

ターミナルで実行すると、非同期バージョンは100以上のインスタンスを生成しました。その他のバージョンのインスタンス数は、すべて1のはずですが、2や3がちらほら。

何がいけない?と思って調べると、map.entrySet().size()も1ではありませんでした。ところが、map.entrySet()やmap.keySet()をiterator()で表示してみると、内容自体は1個でした。

HashSetを使っても、2や3がちらほらありました。HashMapやHashSetはスレッドセーフではないことが原因なんですね。

HashMapをConcurrentHashMapに置き換えたところ、その他のバージョンのインスタンス数は、すべて1になりました。

スレッド同期化Singletonの実験をしているので、ConcurrentHashMapを使わないようにと考えて、最終的には、スレッド数と同じ長さの配列を用意して、最後にユニーク数を集計することにしました。

Main.java最終バージョン

ChocolateBoiler.java

abstractにしたり、Factoryクラスを作っていますが、基本的なところは書籍サンプルのままです。今回のMainクラスでは、fill()やdrain()は呼んでいません。

ChocolateBoilerFactory.java

ChocolateBoilerNoSynchronized.java

非同期バージョン

ChocolateBoilerSynchronized.java

synchronizedバージョン

ChocolateBoilerInitializationOnClassLoaded.java

クラスロード時インスタンス化バージョン

ChocolateBoilerInitializationOnDemandHolder.java

オンデマンドホルダーインスタンス化バージョン

ChocolateBoilerDoubleCheckedLocking.java

ダブルチェックドロッキングバージョン