Frage

private static Callback callback;

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

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

Constructor Foo () kann möglicherweise von mehreren Threads aufgerufen werden. Meine Sorge ist, mit dem privaten statischen Feld ‚Rückruf‘ und die statischen Methode ‚getCallback ()‘.

Wie man sehen kann, jedes Mal ‚getCallback ()‘ genannt wird, weist es einen neuen Wert zu statischem Feld ‚Rückruf‘.

Mein Vermutung ist, dass es nicht sicher ist, fädelt, weil das Schlüsselwort statisch immer auf die Klasse gebunden ist nicht der Fall, so dass Mittel, das statische Feld ‚Rückruf‘ ein Foo kann möglicherweise durch anderen Thread überschrieben werden, der ein anderen Foo () errichtet. Ist das richtig?

Bitte korrigieren Sie mich, wenn ich falsch bin. Dank!

EDIT: Meine Absicht ist ‚Rückruf‘ zu halten irgendwo in der Klasse, also kann ich es später wiederverwenden. Aber das ist nicht einfach, weil Foo aus einer Klasse erweitert, die Konstruktor Mandatierung hat ‚Rückruf‘ weitergegeben werden.

War es hilfreich?

Lösung

Ja, Sie richtig sind. Es ist möglich, dass zwei Instanzen von Foo mit derselben CallBack Instanz, um am Ende, wenn zwei Threads die getCallback() Verfahren gleichzeitig und eine ordnet eine neue CallBack zum statischen Feld eingeben, während die andere dies bereits getan hat, aber noch nicht zurückgekehrt. In diesem Fall ist die beste Fix nicht das statische Feld zu haben, da es keinen Zweck dient. Alternativ machen getCallback() synchronisiert.

Beachten Sie aber, dass es nicht wahr, dass nur die static Keyword-Ergebnisse in Code, der nicht thread wird.

Andere Tipps

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

Option 1: Hier wird alle Instanzen den gleichen Rückruf teilen

private static final Callback callback = new Callback();

public Foo() {
    super(callback);
}

Option 2: hier jede Instanz hat seine eigene Callback

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

Beachten Sie, dass in beiden Fällen, obwohl die Konstruktor Thread-sicher ist, hängt die Thread-Sicherheit der ganzen Klasse über die Umsetzung des Rückrufs. Wenn es wandelbar Staat hat, dann werden Sie potenzielle Probleme haben. Wenn Rückruf unveränderlich ist, dann haben Sie Thread-Sicherheit.

Rückruf wird einen neuen Wert jedes Mal Foo () erhalten wird genannt (auch aus dem gleichen Thread). Ich bin mir nicht ganz sicher, was der Code tun sollte (wenn Sie die statische Variable initialisiert werden soll nur einmal (Singleton), sollten Sie prüfen, ob es noch null in getCallback () ist - und was ist actionCallback?). Für die es Thread-sicher, verwenden synchronisiert.

Ich glaube, Sie es aufsummiert perfekt selbst, aber ohne mehr Details über das, was Sie es versuchen zu erreichen wird schwierig sein, Vorschläge zu machen, Ihr Problem zu beheben.

Eine offensichtliche Frage ist, ob callback statisch sein müssen? Oder könnten Sie es sicher eine Instanz Feld machen, ohne die Funktionalität Ihrer Klasse zu brechen?

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

Es zwei Threads sind die getCallback () -Methode aufrufen, könnten sie die Zeilen wie folgt ausführen:

  1. Thread 1 - Rückruf = new Rückruf ();
  2. Thread 2 - Rückruf = new Rückruf ();
  3. Thread 1 - Rückkehr actionCallback;
  4. Thread 2 - Rückkehr actionCallback;

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

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

Ich hoffe, das hilft.

Was Sie versuchen, ein Singleton-Muster zu tun heißt, wenn Sie eine Suche können Sie die im Allgemeinen eine gute Idee, herauszufinden, warum dieses Muster zu vermeiden, wenn Sie können, aber wenn Sie es brauchen Sie können die folgenden Aktionen aus.

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 Ausführungen sind Thread-sicher.

Haben Sie einen Rückruf wünschen pro Thema, eine pro Objekt oder eine echte Singleton?

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

Bitte beachten Sie, dass ich angenommen habe, dass der Rückruf eine nicht-triviale Konstruktor hat, die Ausnahme vielleicht werfen, die behandelt werden muss, wenn es sich um eine triviale Konstruktor können Sie alle diese vereinfachen viel.

Ein 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;
  }
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top