8

以下のコードのように、ネストされた if を使用して、開発者が常にシングルトンが null であるかどうかを 2 回チェックしているコードに出くわしました。

private static processManager singleton = null;

...

public synchronized static processManager getInsatnce() throws Exception {

    if(singleton == null) {
      if(singleton == null){
             singleton = new processManager();
       }
     }
     return singleton
}

これがなぜなのかはわかりませんが、コードには多数のインスタンスがあるため、理由があると思いますか?

4

5 に答える 5

16

あなたのコードはケースを適切に示していません。これは、意味を成すdouble-checkedイディオムに由来します。

// Double-check idiom for lazy initialization of instance fields.
private volatile FieldType field;
FieldType getField() {
    FieldType result = field;
    if (result == null) { // First check (no locking)
        synchronized(this) {
            result = field;
            if (result == null) // Second check (with locking)
                field = result = computeFieldValue();
        }
    }
    return result;
}

ここでそれについて読んでください。

このイディオムは、インスタンスフィールドにのみ適していることに注意してください。あなたの質問にはstaticフィールドがあります。その場合、はるかに単純なイディオムが主な選択です:怠惰なイニシャルホルダークラスイディオム:

// Lazy initialization holder class idiom for static fields
private static class FieldHolder {
    static final FieldType field = computeFieldValue();
}
static FieldType getField() { return FieldHolder.field; }
于 2013-03-19T11:48:43.857 に答える
6

Double Checked Locking Idiomを達成しようとして失敗しました。最初のnullチェックは、インスタンスがすでに作成されているかどうかを確認することです。作成されている場合はnot null、作成済みのインスタンスを返します。

しかし、条件チェックはcheck-then-act の状況であり、スレッドセーフではないため、2 つ以上のスレッドが値を見て、シングルトンnullの 2 つのインスタンスを作成し、それがdoubletonまたはManyTonになる可能性があります

synchronizedそのため、1 つのスレッドのみがそのブロックに入り、単一のインスタンスのみが作成されるように使用します。

于 2013-03-19T11:54:28.660 に答える
3

Double Checked Lockingについて言及していると思います。このパターンを使用すると、同期が不要な場合に同期を回避できます。

あなたのコードは

private static volatile ProcessManager singleton = null;

public static ProcessManager getInstance() throws Exception {

    if (singleton == null) {
        synchronized (MyClass.class) {
            if (singleton == null) {
                singleton = new ProcessManager();
            }
        }
    }
    return singleton;
}

したがって、シングルトンが null でないことを確認した場合にのみ同期することがわかります。その後、誰かがすでにビルドを開始している場合に備えて再確認します。これが機能するには、シングルトンが である必要があること volatileに注意してください。を忘れた場合に発生する微妙な問題を説明する記事を次に示しvolatileます。

メソッドが同期されているあなたの場合、あなたは正しいです。2度チェックしても意味がありません。

于 2013-03-19T11:51:54.653 に答える
0

この手法はダブルチェックと呼ばれます。

ただし、貼り付けたコードは正しくありません。そうです、そのように null 値を再確認するのは意味がありません。ダブルチェックの正しい実装は次のとおりです。

private static volatile ProcessManager instance = null;

public static ProcessManager getInstance() {
   if (instance == null) {
       synchronized(ProcessManager.class) {
         if (instance == null) {
            instance = new ProcessManager();
         }
      }
   }
   return instance;
}

2 番目の null チェックが ProcessManager.class オブジェクトで同期されることに注意してください。getInstance() メソッドは静的メソッドなので必要です。

于 2013-03-19T11:58:59.747 に答える
0

シングルトンがゲッターでインスタンスを作成するプロパティでない限り、これは意味がありませんが、それでも意味がなく、コードの残りの部分に到達できません。

于 2013-03-19T11:49:50.660 に答える