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

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

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

Der Konstruktor Foo() kann möglicherweise von mehreren Threads aus aufgerufen werden. Mein Anliegen ist das private statische Feld 'Callback' und die statische Methode 'getCallback()'.Hilfe zum Überprüfen des folgenden Codes, ist es threadsicher?

Wie man sieht, weist jedesmal, wenn 'getCallback()' aufgerufen wird, dem statischen Feld 'Callback' einen neuen Wert zu. das statische Feld ‚Callback‘ ein Foo kann möglicherweise durch andere

Meine Vermutung ist, dass es nicht sicher ist, fädelt, weil das Schlüsselwort statische immer auf die Klasse gebunden ist nicht der Fall, so dass Mittel, überschreibt Thread, der ein anderes Foo() erstellt. Ist das richtig?

Bitte korrigieren Sie mich, wenn ich falsch liege. Vielen Dank!

EDIT: Meine Absicht ist es, "Callback" irgendwo in der Klasse zu halten, so dass ich es später wiederverwenden kann. Aber das ist nicht einfach, weil Foo von einer Klasse ausgeht, die einen Konstruktor hat, der 'Rückruf' vorschreibt, um weitergegeben zu werden.

+1

Gute Frage. Diese Fragen sind logisch schwer zu durchdenken. –

+0

Es kompiliert nicht. Woher kommt actionCallback? In der Regel initialisieren Sie ein statisches Feld nicht über einen Konstruktor, es sei denn, Sie möchten etwas unklar sein. –

+0

Sorry, 'actionCallback' sollte 'Rückruf' sein. Ich beabsichtige, den Rückruf in der Klasse zu behalten, damit ich ihn später wiederverwenden kann. Aber das ist nicht einfach, weil Foo von einer Klasse ausgeht, die einen Konstruktor hat, der 'Rückruf' vorschreibt, um weitergegeben zu werden. – His

Antwort

6

Ja, Sie haben Recht. Es ist möglich, dass zwei Instanzen von Foo mit derselben CallBack Instanz enden, wenn zwei Threads gleichzeitig die Methode getCallback() eingeben und eine neue CallBack dem statischen Feld zuweist, während die andere bereits dies getan, aber noch nicht zurückgegeben hat. In diesem Fall ist die beste Lösung, das statische Feld nicht zu haben, da es keinen Zweck erfüllt. Alternativ können Sie auch getCallback() synchronisieren.

Aber beachten Sie, dass es nicht wahr ist, dass nur das static Schlüsselwort in Code, der nicht threadsafe ist.

3

Callback erhält jedes Mal, wenn Foo() aufgerufen wird, einen neuen Wert (sogar aus demselben Thread). Ich bin nicht ganz sicher, was Ihr Code tun sollte (wenn Sie die statische Variable nur einmal (Singleton) initialisieren wollen, sollten Sie überprüfen, ob es in getCallback() immer noch null ist - und was ist actionCallback?). Um es threadsicher zu machen, benutze es synchron.

2

Ich denke, dass Sie es perfekt selbst zusammengefasst haben, aber ohne weitere Details über das, was Sie erreichen wollen, wird es schwierig sein, Vorschläge zu machen, um Ihr Problem zu beheben.

Eine offensichtliche Frage ist, muss callback statisch sein? Oder könnten Sie es sicher zu einem Instanzfeld machen, ohne die Funktionalität Ihrer Klasse zu beeinträchtigen?

5

Es ist nicht Thread-sicher. Versuchen Sie diese Alternativen:

Option 1: hier alle Instanzen teilen sich die gleiche Rückruf

private static final Callback callback = new Callback(); 

public Foo() { 
    super(callback); 
} 

Option 2: hier jede Instanz hat seine eigene Rückruf

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

Beachten Sie, dass in beiden Fällen, obwohl die Konstruktor ist Thread-sicher, die Thread-Sicherheit der gesamten Klasse hängt von der Implementierung von Callback ab. Wenn es einen veränderbaren Zustand hat, haben Sie potentielle Probleme. Wenn Callback unveränderbar ist, haben Sie Thread-Sicherheit.

2

Ich weiß, dass es beantwortet wurde, aber das Warum wurde nicht wirklich detailliert.

Es zwei Fäden werden die getCallback() Methode aufrufen, könnten sie die Linien wie folgt ausführen:

  1. Thread 1 - Rückruf = new Rückruf();
  2. Thread 2 - Rückruf = neuer Rückruf();
  3. Gewinde 1 - RücklaufaktionCallback;
  4. Thread 2 - RückgabeaktionCallback;

In diesem Fall wird der Rückruf bei (2) erzeugt würde in beide (3) zurückgeführt werden und (4.)

Die Lösung scheint zu fragen, warum, wenn es Rückruf staticly definiert ist spezifisch für die Instanz nicht Klasse.

Ich hoffe, dass hilft.

1

Was Sie versuchen, ist ein Singleton-Muster, wenn Sie eine Suche durchführen, können Sie herausfinden, warum es im Allgemeinen eine gute Idee ist, dieses Muster zu vermeiden, wenn Sie können, aber wenn Sie es brauchen, können Sie Folgendes tun.

private static final Callback CALLBACK= new Callback(); 

Oder wenn Sie einen faulen Singleton benötigen, können Sie tun

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

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

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

Beide Implementierungen Thread-sicher sind.

1

Möchten Sie einen Rückruf pro Thread, einen pro Objekt oder einen echten Singleton?

Einige Skizzen, wie die verschiedenen Varianten zu tun - nur von der Oberseite meines Kopfes, nehmen Sie dies nicht zu wörtlich :)

Bitte beachten Sie, dass ich, dass der Rückruf einen nicht-trivialen Konstruktor hat angenommen habe, dass könnte eine Exception auslösen, die behandelt werden muss. Wenn es ein trivialer Konstruktor ist, können Sie all diese Dinge sehr vereinfachen.

One pro Thema:

private static ThreadLocal<Callback> callback; 

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

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

Rückruf für alle Threads:

private final static Callback callback; 

    static { 
     callback = new Callback(); 
    } 

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

    private static Callback getCallback() 
    { 
     return callback; 
    } 

Und für Vollständigkeit, ein Rückruf pro Objekt:

private Callback callback; 

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

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