3
private static Callback callback;

public Foo()
{
    super(getCallback());
}

private static Callback getCallback()
{
    callback = new Callback();
    return callback;
}

コンストラクター Foo() は、複数のスレッドから呼び出される可能性があります。私の懸念は、プライベート静的フィールド「callback」と静的メソッド「getCallback()」にあります。

ご覧のとおり、「getCallback()」が呼び出されるたびに、静的フィールド「callback」に新しい値が割り当てられます。

私の推測では、キーワードstaticは常にインスタンスではなくクラスにアタッチされているため、スレッドセーフではないということです。つまり、Foo の静的フィールド 'callback' は、別の Foo() を構築している他のスレッドによって上書きされる可能性があります。 . これは正しいです?

間違っている場合は修正してください。ありがとう!

編集:私の意図は、「コールバック」をクラスのどこかに保持することです。そのため、後で再利用できます。しかし、これは簡単ではありません。なぜなら、Foo は、「コールバック」の受け渡しを義務付けるコンストラクタを持つクラスから拡張されているからです。

4

7 に答える 7

6

はい。それで合っています。2 つのスレッドが同時にメソッドに入り、一方が static フィールドに new を割り当て、もう一方が既にこれを行っているがまだ返されていない場合、 の 2 つのインスタンスFooが同じインスタンスになる可能性があります。この場合、静的フィールドは何の役にも立たないため、静的フィールドを持たないことが最善の解決策です。または、同期化します。CallBackgetCallback()CallBackgetCallback()

ただし、キーワードだけがスレッドセーフではないコードになるというのは正しくないことに注意してください。static

于 2009-06-01T09:41:57.150 に答える
5

スレッドセーフではありません。次の方法を試してください。

オプション 1: すべてのインスタンスが同じコールバックを共有する場合

private static final Callback callback = new Callback();

public Foo() {
    super(callback);
}

オプション 2: ここでは、各インスタンスに独自のコールバックがあります

public Foo() {
    super(new Callback());
}

どちらの場合も、コンストラクターはスレッド セーフですが、クラス全体のスレッド セーフは Callback の実装に依存することに注意してください。可変状態の場合、潜在的な問題が発生します。Callback が不変の場合、スレッドセーフです。

于 2009-06-01T09:52:12.387 に答える
3

コールバックは、Foo() が呼び出されるたびに (同じスレッドからでも) 新しい値を取得します。コードが何をすべきかよくわかりません(静的変数を1回だけ(シングルトン)初期化したい場合は、getCallback()でまだnullであるかどうかを確認する必要があります-そしてactionCallbackとは何ですか?)。スレッドセーフにするには、synchronized を使用します。

于 2009-06-01T09:43:03.327 に答える
2

回答があったことは知っていますが、その理由は実際には詳しく説明されていません。

2 つのスレッドが getCallback() メソッドを呼び出している場合、次のように行を実行できます。

  1. スレッド 1 - コールバック = 新しいコールバック();
  2. スレッド 2 - callback = new Callback();
  3. スレッド 1 - actionCallback を返します。
  4. スレッド 2 - actionCallback を返します。

この場合、(2.) で生成されたコールバックは、(3.) と (4.) の両方で返されます。

解決策は、コールバックがクラスではなくインスタンスに固有のものである場合、なぜコールバックが静的に定義されているのかを尋ねることです。

それが役立つことを願っています。

于 2009-06-01T16:58:15.017 に答える
2

あなたはそれを自分で完全に要約したと思いますが、あなたが達成しようとしていることについての詳細がなければ、問題を解決するための提案をするのは難しいでしょう.

明らかな質問の 1 つは、callback静的である必要があるかどうかです。または、クラスの機能を壊さずに安全にインスタンス フィールドにすることができますか?

于 2009-06-01T09:44:01.200 に答える
1

スレッドごとに 1 つのコールバック、オブジェクトごとに 1 つ、または真のシングルトンが必要ですか?

さまざまなバリエーションを実行する方法に関するいくつかのスケッチ-頭のてっぺんから、これらを文字通りに解釈しないでください:)

Callback には、処理が必要な例外をスローする可能性のある自明でないコンストラクターがあると想定していることに注意してください。それが自明なコンストラクターである場合、これらすべてを大幅に単純化できます。

スレッドごとに 1 つ:

  private static ThreadLocal<Callback> callback;

  public Foo()
  {
      super(getCallback());
  }

  private static Callback getCallback()
  {
      if ( callback.get() == null ) 
          callback.set(new Callback());
      return callback.get();
  }

すべてのスレッドに対する単一のコールバック:

  private final static Callback callback;

  static {
      callback = new Callback(); 
  }

  public Foo()
  {
      super(getCallback());
  }

  private static Callback getCallback()
  {
      return callback;
  }

そして、完全を期すために、オブジェクトごとに 1 つのコールバック:

  private Callback callback;

  public Foo()
  {
      super(getCallback());
  }

  private Callback getCallback()
  {
      callback = new Callback();
      return callback;
  }
于 2009-06-02T07:42:02.823 に答える
1

あなたがやろうとしていることはシングルトンパターンと呼ばれます。検索を行うと、可能であればこのパターンを避けることが一般的に良い考えである理由を見つけることができますが、必要な場合は次のことができます.

private static final Callback CALLBACK= new Callback();

または、怠惰なシングルトンが必要な場合は、次のことができます

public class Foo {
   class CallbackHolder {
       static final Callback CALLBACK= new Callback();
   }

   public static Callback getCallback() {
      return CallbackHolder.CALLBACK;
   }

public Foo() {
    super(getCallback());
}

どちらの実装もスレッドセーフです。

于 2009-06-02T06:22:57.377 に答える