4

私はシングルトンの設計パターンを調査していましたが、クラスを開発しました...

public class SingletonObject {
  private static SingletonObject ref;       
  private SingletonObject () { //private constructor
  }     
  public static synchronized SingletonObject getSingletonObject() {
    if (ref == null)
      ref = new SingletonObject();
    return ref;
  } 

  public Object clone() throws CloneNotSupportedException {
    throw new CloneNotSupportedException ();
  }
}

しかし、同期は非常にコストがかかるため、遅延作成されたインスタンスではなく、熱心に作成されたインスタンスの新しい設計に移行します..

public class Singleton {
  private static Singleton uniqueInstance = new Singleton();
  private Singleton() {
  }
  public static Singleton getInstance() {
    return uniqueInstance;
  }
}

しかし、2番目のデザインが前のデザインよりも優れている点を教えてください..!!

4

6 に答える 6

5

Josh Blochは、列挙型の使用を推奨しています。

   public enum Foo {
       INSTANCE;
   }

説明については、Google I / O2008での彼のEffectiveJavaReloadedトークを参照してください。

要約すれば:

「このアプローチは、より簡潔で、シリアル化機構を無料で提供し、高度なシリアル化またはリフレクション攻撃に直面した場合でも、複数のインスタンス化に対する強力な保証を提供することを除いて、パブリックフィールドアプローチと機能的に同等です。まだ広く採用されていないので、シングルエレメント列挙型はシングルトンを実装するための最良の方法です。」

于 2012-04-20T17:40:33.510 に答える
2

あなたが述べたように、2番目のソリューションは同期コストを回避します。また、よりシンプルでクリーンなため、読みやすく、維持しやすくなっています。ただし、少し問題があります。 のfinal修飾子がprivate static Singleton uniqueInstanceありません。これは、同時実行環境でスレッドセーフであることが保証されない可能性があることを意味します (ただし、この具体的なケースでは、これが実際に目に見える問題を引き起こすとは思いません. ..しかし、スレッドの安全性に関しては安全側にいるほうがよいでしょう)。幸いなことに、これは簡単に修正できます。

もう 1 つの欠点は、クラスSingletonが参照されるとすぐに、実際には使用されない場合でもシングルトン オブジェクトが作成されることです。作成にコストがかかる場合、これは問題になる可能性があります。Initialization-on-demand Holderイディオムで回避できます。

于 2012-04-20T17:36:44.793 に答える
1

熱心なインスタンス化と遅延初期化

2番目の設計では、遅延初期化の代わりに熱心なインスタンス化を使用します。これは必ずしも良いか悪いかではなく、アプリケーションにどちらが適切かによって異なります。

一般に、次の場合は遅延初期化を使用することをお勧めします。

  • アプリケーションがクラスのインスタンスを作成する必要がない可能性がある場合
  • クラスのインスタンス化に費用がかかり、操作をできるだけ遅くする方がよい場合

スレッドの安全性とパフォーマンス

2番目の設計のもう1つの利点は、パフォーマンスが向上することです。マルチスレッド環境では、最初の設計では、インスタンスがすでにインスタンス化されている場合でも、インスタンスを取得する前に各スレッドがロックを取得する必要があります。これを回避するには、ダブルチェックロックまたはBillPughアプローチを使用します。

列挙型ウェイ

両方の設計とは異なるアプローチは、単一の値を持つ列挙型を使用する列挙型の方法です。列挙型にはメソッドとメンバー変数を含めることができるため、通常のクラスのような動作を模倣できます。これは、シングルトンを作成するための優れた鉄壁の方法であり、JoshuaBlochによって推奨されています。

于 2012-04-20T17:40:36.333 に答える
1

2 番目のデザインは、もう少し簡潔で読みやすいという点で優れています。また、おっしゃったように、シングルトンを使用するたびに同期するコストを回避できます。

2 番目の設計の欠点の 1 つは、シングルトンを使用しない場合でも、シングルトンをインスタンス化するためのメモリと CPU のコストが発生することです。

于 2012-04-20T17:35:32.693 に答える
0

また、 singleton を指す変数を作成する必要がありますfinal

public class Singleton {
    private static final Singleton uniqueInstance = new Singleton();
    private Singleton() {}
    public static Singleton getInstance() {
        return uniqueInstance;
    }
}

この実装では、ClassLoader がシングルトンのインスタンスをインスタンス化し、スレッド セーフを提供します。別のパターンでは を使用していますenumが、個人的にはその実装はコードの匂いだと考えています。

于 2012-04-20T17:38:02.000 に答える
0

いくつかのメモ:

  1. 最初の例は、マルチスレッドのシナリオでは期待どおりに機能しません。ref はvolatile可変である必要があり、ロックの再確認が必要です。

  2. synchronization2 番目の例には追加料金はありません。Lazy Singletonただし、熱心なシングルトンの代わりに効果的に実装できます。

詳細については、以下の SE の質問を参照してください。

この二重チェック ロックの例で volatile が使用されている理由

于 2016-07-07T10:59:44.573 に答える