2009-06-01 2 views
3
private static Callback callback; 

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

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

コンストラクタFoo()は、複数のスレッドから呼び出される可能性があります。私の懸念事項は、プライベート静的フィールド 'コールバック'と静的メソッド 'getCallback()'です。次のコードを見直しても安全ですか?

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

マイ推測手段は、フーの静的フィールド「コールバック」は、潜在的に他で上書きすることができるようにキーワード静的は常に、クラスではないインスタンスに接続されているので、それはスレッドセーフではないということですスレッドは別のFoo()を構築しています。これは正しいです?

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

編集:私の意図は、クラスのどこかでコールバックを保持することです、私は後でそれを再利用することができます。しかし、これは容易ではありません.Fooは渡される 'コールバック'を強制するコンストラクタを持つクラスから継承されるからです。

+1

良い質問。これらの問題は、論理的に自分自身で考えるのは難しいです。 –

+0

コンパイルされません。 actionCallbackはどこから来たのですか?原則として、コンストラクタを介して静的フィールドを初期化しないでください。混乱を避ける必要があります。 –

+0

申し訳ありませんが、 'actionCallback'は 'コールバック'とされていました。私の意図は、クラスのどこかで 'コールバック'を保持することです、私は後でそれを再利用することができます。しかし、これは容易ではありません.Fooは渡される 'コールバック'を強制するコンストラクタを持つクラスから継承されるからです。 – His

答えて

6

はい、正しいです。 Fooの2つのインスタンスが同じCallBackインスタンスになる可能性があります.2つのスレッドが同時にgetCallback()メソッドに入り、もう1つがstaticフィールドに新しいCallBackを割り当てますが、もう一方はすでに完了していますが返されていません。この場合、最良の修正は目的を果たさないため、静的フィールドを持たないことです。あるいは、getCallback()を同期させます。

ただし、ではないことに注意してください。staticキーワードのみがスレッドセーフではないコードになります。

3

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

2

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

明白な質問の1つは、callbackは静的でなければなりませんか?または、クラスの機能を損なうことなくインスタンスフィールドを安全に作成できますか?

5

スレッドセーフではありません。これらの代替案を試してください:

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

private static final Callback callback = new Callback(); 

public Foo() { 
    super(callback); 
} 

オプション2:ここでは、各インスタンスは、両方のケースで、けれどもことを、独自のコールバック

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

注意を持っていますコンストラクタはスレッドセーフであり、クラス全体のスレッドセーフティはコールバックの実装に依存します。可変状態の場合、潜在的な問題が発生します。コールバックが不変の場合は、スレッドセーフです。

2

私はそれが答えられていることを知っていますが、なぜ実際に詳細されていません。

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

  1. スレッド1 - コールバックは=新しいコールバックを();
  2. スレッド2 - コールバック=新しいコールバック();
  3. スレッド1 - return actionCallback;
  4. スレッド2 - return actionCallback;
  5. この場合

、(2)で生成されたコールバックは(3)の両方に返されると、(4)

ソリューションは、それならば、コールバックは、静的に定義された理由を尋ねることであるように見えるでしょうクラスではないインスタンスに固有です。

私は役立つことを願っています。

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()); 
} 

を行うことができます。

1

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

異なる変形を行う方法についていくつかのスケッチ - ちょうど私の頭の上からは、あまりにも文字通りこれらを取ることはありません:)

私はコールバックが非自明なコンストラクタを持っていると仮定してきたことにご注意ください簡単なコンストラクタであれば、これらのすべてを単純化することができます。 completnessため

private final static Callback callback; 

    static { 
     callback = new Callback(); 
    } 

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

    private static Callback getCallback() 
    { 
     return 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 Callback callback; 

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

    private Callback getCallback() 
    { 
     callback = new Callback(); 
     return callback; 
    } 
関連する問題