2015-11-12 4 views
7

あなたがこれを行うことができ、Javaの静的シングルトンの遅延初期化やって:最初のgetInstance()が呼び出されるまでBob()が作成されていないアクセス時に内部クラスSingletonWrapperのみがロードされているので静的なシングルトンと同様の方法で、Javaメンバーの無駄な遅延ロードを取得できますか?

public class Bob { 

    private static class SingletonWrapper { 
     private static final Bob instance = new Bob(); 
    } 

    public static Bob getInstance() { 
     return SingletonWrapper.instance; 
    } 

} 

を。

私の質問は、非静的コンテキストでメンバー変数の遅延インスタンス化を行うために使用できる類似のトリックがあるかどうかです。

public class Bob { 

    // Clearly this doesn't work as not lazy 
    private final InnerWrapper wrapper = new InnerWrapper(); 

    private class InnerWrapper { 
     private final Jane jane = new Jane(); 
    } 

    public Jane getJane() { 
     return wrapper.jane; 
    } 

} 

我々はBobJaneのインスタンスがあり、ダブルチェックロックまたはAtomicReferenceを使用せずにオンデマンドでのみ作成されたインスタンスを安全にスレッド持つことができますどのような方法があります。理想的には、getメソッドはこれらの例のように単純なままにしておく必要がありますが、可能でない場合はgetメソッドの最も簡単で高速な(最も効率的な)実行が理想的です。

+0

@assyliasをコメントはそれが遅延初期化しないだろう言うように。 'Bob 'を作成するとすぐに、いつも即座に' Jane'を作成します。 –

+0

私はあまりにも速く読んでいません - あなたがAtomicReferenceを望んでいない理由は何ですか? CHMオプションよりも優れたパフォーマンスを発揮するでしょう。 – assylias

+0

@assylias特に理由はありません。基本的に私は自分のオプションが何であるか知りたがっています。スタティックラッパートリックはシングルトンの初期化を怠っていることを考慮すると、怠惰なメンバー初期化のために似たようなことはできません。 –

答えて

8

いいえ、クラスの初期化のような型をインスタンス化するための同期ルールはありません。自分で追加する必要があります。あなたが二重チェックされたロックまたは他のいくつかのメカニズムでそれをするかどうかはあなた次第です。

Java 8以降、私はConcurrentHashMap#computeIfAbsentを使用して怠惰を達成したいと考えています。

class Bob { 
    private final ConcurrentHashMap<String, Jane> instance = new ConcurrentHashMap<>(1); 

    public Jane getJane() { 
     return instance.computeIfAbsent("KEY", k -> new Jane()); // use whatever constant key 
    } 
} 

また、スレッドセーフな制約なしに遅延初期化のためのthese solutionsもあります。私はマルチスレッドの文脈のためにそれらをきれいに適応させることができませんでした。

コメントに記載されているように、二重チェックロックは、実装を隠すためのすべての毛羽立ちを含まないため、これらのソリューションより常に高速です。

+0

それはクリーンなコードですが、どのように性能が比較されますか? –

+0

余分なチェックがないため、ダブルチェックロックがおそらく最も速くなります。インスタンスを取得するために必要なことを最大限に実行しています。 –

+1

論理が似ているにもかかわらず、Guavaを使った私の冗長な解決策よりも良い方法 –

2

あなたはグアバのキャッシュを使用することができます。

public class Bob { 
    private final static Object KEY = new Object(); 

    private final Cache<Object, Jane> cache = 
     CacheBuilder.newBuilder() 
        .build(new CacheLoader<Object, Jane>() { 
           @Override 
           public Jane load() { 
            return new Jane(); 
           } 
          }); 

    public Jane getJane() { 
     return cache.get(KEY); 
    } 

} 
+0

これは、キャッシュの主な使用例ではありません。自動追い出しです。 concurrentHashMapは作業を行い、guavaキャッシュよりも優れたパフォーマンスを発揮します – Zava

関連する問題