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

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

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

構造函數Foo()可能會被多個線程調用。我關心的是私有靜態字段'callback'和靜態方法'getCallback()'。幫忙查看下面的代碼,線程安全嗎?

如可以看到的,每一次「getCallback()」被調用時,它分配一個新的值,以靜態字段「回調」。

猜測是,它不是線程安全的,因爲關鍵字靜態始終附加到類而不是實例,這樣就意味着,一個Foo的靜態字段「回調」有可能被其他覆蓋正在構造另一個Foo()的線程。它是否正確?

如果我錯了,請糾正我。謝謝!

編輯:我的意圖是保持'回調'在類的某個地方,所以我可以在以後重複使用。但是這並不容易,因爲Foo從一個具有構造函數的類中繼承,該類需要傳遞'callback'。

+1

好問題。這些問題很難通過自己邏輯思考。 – 2009-06-01 09:53:21

回答

6

是的,你是對的。這是可能的Foo兩個實例具有相同CallBack情況下結束,當兩個線程同時進入getCallback()方法之一,而另一個已經做到了這一點,但沒有返回分配一個新的CallBack到靜態字段。在這種情況下,最好的解決辦法是不要有靜態字段,因爲它沒有任何用處。或者,使getCallback()同步。

但請注意,它是而不是確實只有static關鍵字會導致非線程安全的代碼。

3

每次調用都會得到一個新的值Foo()被調用(即使從同一個線程)。我不太清楚你的代碼應該做什麼(如果你只想初始化靜態變量一次(singleton),你應該檢查getCallback()是否仍然爲null)以及什麼是actionCallback?)。爲了使其線程安全,請使用synchronized。

2

我認爲你自己總結得很完美,但沒有更多關於你想要實現的細節,提出解決問題的建議將會非常棘手。

一個明顯的問題是,是否callback必須是靜態的?或者你可以安全地將它作爲一個實例字段而不會破壞你的類的功能?

5

它不是線程安全的。嘗試這些替代選擇:

選項1:這裏的所有實例共享相同的回調

private static final Callback callback = new Callback(); 

public Foo() { 
    super(callback); 
} 

選項2:這裏的每個實例都有自己的回調

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

注意,在這兩種情況下,雖然構造函數是線程安全的,整個類的線程安全性取決於Callback的實現。如果它有可變狀態,那麼你將會有潛在的問題。如果回調是不可變的,那麼你有線程安全。

2

我知道它已被回答,但爲什麼沒有真正詳細。

它兩個線程調用getCallback()方法,如下所示它們可以執行行:

  1. 線程1 - 回調=新回調();
  2. 線程2 - 回調=新回調();
  3. 線程1 - 返回actionCallback;
  4. 線程2 - 返回actionCallback;

在這種情況下,在(2)中產生的回調將在兩個(3)返回,並(4)

溶液似乎是問爲什麼回調staticly如果它定義特定於不是類的實例。

我希望有幫助。

1

你所試圖做的是稱爲Singleton模式,如果你做一個搜索,你可以找出爲什麼它通常是一個好主意,如果你能避免這個模式,但是如果你需要它,你可以做到以下幾點。

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

你想每一個線程回調,每一個對象,或者一個真正的單身?

如何做不同的變體的一些草圖 - 只是從我的頭頂,不採取這些文生義:)

請注意,我假設回調有一個平凡的構造函數可能會拋出需要處理的異常,如果它是一個簡單的構造函數,則可以簡化所有這些。

每一個線程:

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

而且,對於completness,每個對象一個回調:

private Callback callback; 

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

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