• Share
  • Email
  • Embed
  • Like
  • Save
  • Private Content
第1回 チキチキ『( ゜ェ゜)・;'.、ゴフッ』 - シングルトンパターン(Java)
 

第1回 チキチキ『( ゜ェ゜)・;'.、ゴフッ』 - シングルトンパターン(Java)

on

  • 3,696 views

 

Statistics

Views

Total Views
3,696
Views on SlideShare
3,687
Embed Views
9

Actions

Likes
4
Downloads
15
Comments
0

3 Embeds 9

http://s.deeeki.com 7
http://twitter.com 1
http://b.hatena.ne.jp 1

Accessibility

Categories

Upload Details

Uploaded via as Apple Keynote

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment
  • \n
  • かとうです。最近徐々に実体を晒していますが、しらない人いると思いますが、ダイちゃんの上司といえばわかりますかね。技術的な突き上げが厳しいので、頑張っている上司ですね。はい。\n最近はScalaの記事書きました。入門者用の記事なのでわかりやすいと思います。java-jaでは、yuroyoroさんにレビュー頼みました。ありがとうございました。\nそれと、DDDも結構ディープにやってます。2003年の発刊で待望の和訳がでました。ファウラー氏もケットベック氏も絶賛。日本だと和田さん筆頭にJavaEE勉強会により貢献が大きいですね。私とダイちゃんで主に2部の\n
  • シングルトンとは、1個しかインスタンスを作らないというパターンで、プログラマが注意をしてインスタンスを1個しか作れないではなく、それをプログラム上で表現するという意味です。\n
  • パターンを利用しないで自由にnewさせている場合は、インスタンス数を制御できません。これはプログラマが頑張って制御するのではなく、どのようにしても1つだけにする仕組みを提供することが目的です。\n
  • 例えば、キャッシュの場合ですね。\nインスタンスを定数化して、コンストラクタをprivateにします。初期化はイーガーになりますが、典型的にはこれで十分です。インスタンス定数はどこでも\n
  • 次は、getInstanceというファクトリメソッドを用意しています。\nJVMの最適化を考えればそれほど神経質になることではないと思いますが、この場合のメリットは、APIによって内部実装を隠蔽できることですね。\n\n
  • <<もうひとつのメソッドを介することによるメリット>>\nシングルトンは「クラスのインスタンスが1つしか生成されない」という意味ですが、\nそのインスタンスのコンテキスト\nあるクラスの「特定の」インスタンスが1つしか生成されない、解釈することができます。\n・たとえば、遅延初期化や、インスタンスをスレッド毎に作るなどです。\n・この例では、 getInstanceを呼び出したスレッドごとに唯一のインスタンスを返している。\n ・内部の実装ではThreadLocalをサブクラッシングして、initValueで初期値を返しています。この初期化はgetがトリガーとなるので、実質遅延初期化のシングルトンになります。\n
  • テスト対象がシングルトンと依存している場合は、テストが厄介になります。\nCacheのインスタンスをモック実装に置き換えたいとします。\nしかし、privateコンストラクタだとサブクラス化できません。コンストラクタをprotectedにする場合はサブクラス化できますが、それだけインスタンスを制限できないリスクがあります。トレードオフですね。\nもう一つ方法は、Cacheの振る舞いをインターフェイスを定義し、それのシングルトンとして実装と、モックとしての実装をテストのときに使い分ける方法があります。\n
  • シングルトンにもインターフェイスを用意すれば、クライアントに対してJMockとかでモック化するなり、ダミーのモック実装を作りなりができます。これでも、Cache型を使う限り置いてはインスタンスの数の管理が結構難しい印象です。\n
  • 扱い方次第でグローバル変数になってしまう。\nシングルトンはコードの中のどこからでも同一のインスタンスにアクセスできるから。\n\n\n
  • readObjectメソッドは新たに生成されたオブジェクトを返すので、デシリアライズするとシングルトンとして破綻するんですね。\n
  • Java5以降であれば、enumに使えばシングルトンにできて、先ほどのシリアライズが絡んでも唯一無二のインスタンスが保証されます。シリアライズを念頭に置くならenumが一番安全です。宣言された定数以外にインスタンスがないことをJVMが保証します。\nEffiective Java 第二版 項目77 「インスタンス制御に対してはreadResolveよりenum型を選ぶ」です。\n
  • シングルトンですね。EnumはSerializableを実装していて\n
  • \n
  • 遅延初期化するシングルトンの典型的な例です。最初のgetInstanceメソッドの呼び出しで初期化されます。複数スレッドでこのメソッドを呼び出した際に、複数回の初期化が行われるのを防ぐためと、他のスレッドに初期化済みであることを伝えるために、固有ロックをかけています。\n
  • インスタンスのフィールドを内部クラスに持つパターンです。\n遅延初期化ホルダークラスイデオムとかいいます。\ngetInstanceメソッドが初めて呼び出された時に、初めてInstanceHolder.INSTANCEを読み出し、それによりInstanceHolderが初期化されます。\nこのイデオムの美しさは、getInstanceメソッドは同期されておらず、フィールドアクセスだけを行うことです。したがって、遅延初期化ではアクセスのコストが実質的に増えません。\n最新のJVMはクラスを初期化するためだけにフィールドへのアクセスを同期します。一旦、クラスが初期化されれば、その後のフィールドへのアクセスに何らかの検査や同期がかかわらないように、JVMはコードを修正します。\n\n
  • これはここで全部話せる内容でないですが、ダブルチェッキングロジックのパターンです。Java1.4では正しく動きません。1.5以降です。固有ロックによるロックのコストを減らすのが目的なのですが、なにぶんややこしい。こういうコードは書くべきでないと思います。\n(1)でメインメモリから最新の値を取得します。\n(2)ではvalotileフィールドをチェックしているので(3)で固有ロックよりコストが下さげます。nullの場合は(3)で固有ロックでロックを獲得。\n(3)ロック獲得後は他のスレッドでアンロック前に発生した変更が、事前発生(happens-before)の仕様で最新のinstanceが見えるようになります。他のスレッドによって、すでに初期化済みであれば、ロックを解放してinstanceを返す。未初期化なら初期化してinstanceを返す。固有ロックを抜けるときにこの変更はメインメモリに伝わり、他のスレッドから見えるようになります。\n・こういうコードは理解が難しい\n・メモリモデルに関係するので厄介。できるだけ回避したほうがいいと思います。\n
  • \n
  • \n
  • Eagerなシングルトンですね。\n

第1回 チキチキ『( ゜ェ゜)・;'.、ゴフッ』 - シングルトンパターン(Java) 第1回 チキチキ『( ゜ェ゜)・;'.、ゴフッ』 - シングルトンパターン(Java) Presentation Transcript

  • (Java)@j5ik2o
  • @j5ik2o Scala 6 5 Java Scala DDD( ) (4,5,6 )
  • Singleton ) 1GoF
  • newHoge a = new Hoge(); // 1Hoge b = new Hoge(); // 2 NG 1
  • public class Cache { // public static final Cache INSTANCE = newCache(); private Cache() { } // new public void put(String key, Object value){ ... } public Object get(String key) { ... }}Cache.INSTANCE.put(key, value)Object value = Cache.INSTANCE.get(key)
  • public class Cache { private static final Cache INSTANCE = new Cache(); private Cache() { } public static Cache getInstance() { return INSTNACE; } public void put(String key, Object value){ ... } public Object get(String key) { ... }}Cache.getInstance().put(key, value)Object value = Cache.getInstance().get(key)
  • public class Cache { private static ThreadLocal<Cache> threadLocal =new ThreadLocal<Cache>() { @Override protected Cache initialValue() { return new Cache(); } }; public static Cache getInstnace() { return threadLocal.get(); } public Object get(String key) { /* ... */ } public void put(String key, Object value) { /* ... */ }}
  • 1:Effective Java 3public class CacheClient { // public void process() { getCache().put(...); // ... } // Cache Cache getCache() { return Cache.getInstance(); // ↑ // private // new Cache() { ... } // ... }}
  • public class SingletonCache implements Cache { private static SingletonCache instance; public static SingletonCache getInstnace() { return instance; } @Override public Object get(String key) { /* ... */ } @Override public void put(String key, Object value) { /* ... */ }}public class CacheClient { // ... Cache getCache() { return new Cache(){ /* */ }; }}
  • 2: P40-41 singleton
  • 3: readObject w( o )w!!!Serializable transient ... readResolve (GC) ... private Object readResolve() throws ObjectStreamException { return INSTANCE; // }
  • enumpublic enum Cache { INSTANCE; public vod put(String key, Objectvalue) { /* ... */ } public Object get(String key) {/* ...*/ }}Cache.INSTANCE.put(key, value);
  • enum Jad ...public final class Cache extends Enum<Cache>{ public static final EnumSingleton INSTANCE; private static final Cache $VALUES[]; static { INSTANCE = newEnumSingleton("INSTANCE", 0); $VALUES = (new Cache[] { INSTANCE }); } private Cache(String s, int i){ super(s, i); } // values, valueOf ...}
  • (´ ∀ )public class Singleton { private static Singleton instance; public synchronized static SingletongetInstance() { if (instance == null) { instance = new Singleton(); } return instance; }}
  • ( д ) ?!public class Singleton { // private static class InstanceHolder { private static final Singleton INSTANCE = newSingleton(); } public static Singleton getInstance() { return InstanceHolder.INSTANCE; }}
  • ..(llil!´Д`lil)n{…??public class Singleton { private static volatile Singleton instance public static Singleton getInstance() { Singleton result = instance; // (1) if (result == null) { // (2) => synchronized (Singleton.class) { // (3) : result = instance; // (4) if (result == null) { // (5) result = instance = new Singleton(); // (6) } } // : } return result;}
  • getInstnace ” ”
  • Scala objectobject Cache { def put(key:String, value:Any):Unit= ... def get(key:String):Any = ...}Cache.put(key, value)val value = Cache.get(key)
  • object Singletonpublic final class Cache$ implements ScalaObject{ public static final Cache$ MODULE$ = newCache$(); private Cache$() { /* ... */ } public void put(String key, Object value) { /* ...*/ } public Object get(String key) { /* ... */ }}Cache$.MODULE$.put(key, value)Object value = Cache$.MODULE$.get(key)