Domanda

private static Callback callback;

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

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

Constructor Foo () può potenzialmente essere chiamato da più thread. La mia preoccupazione è con il campo 'richiamata' private static e il metodo statico 'getCallback ()'.

Come si può vedere, ogni volta 'getCallback ()' si chiama, assegna un nuovo valore al campo 'richiamata' statica.

Il mio indovinare è che non è thread-safe perché la parola chiave static è sempre attaccato alla classe non l'istanza, in modo che significa, il campo statico 'richiamata' di un Foo possono potenzialmente essere sovrascritti da altri thread che sta costruendo un'altra Foo (). È corretto?

Si prega di correggermi se sbaglio. Grazie!

EDIT: La mia intenzione è quella di mantenere 'richiamata' da qualche parte nella classe, quindi posso riutilizzare in un secondo momento. Ma questo non è facile, perché Foo si estende da una classe che ha il costruttore di mandato 'richiamata' da trasmettere.

È stato utile?

Soluzione

Sì, lei ha ragione. E 'possibile per due istanze di Foo per finire con la stessa istanza CallBack quando due thread entrano nel metodo getCallback() simultaneamente e si assegna una nuova CallBack al campo statico, mentre l'altro ha già fatto ma non ancora restituito. In questo caso, la migliore soluzione è di non avere il campo statico, dato che non serve a nulla. In alternativa, fare getCallback() sincronizzato.

Ma si noti che si tratta di non vero che solo i static parola chiave Risultati in codice che non è threadsafe.

Altri suggerimenti

Non è thread-safe. Prova queste alternative:

Opzione 1: qui tutte le istanze condividono lo stesso callback

private static final Callback callback = new Callback();

public Foo() {
    super(callback);
}

Opzione 2: qui ogni istanza ha il suo callback

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

Si noti che in entrambi i casi, anche se il costruttore è thread-safe, il filo di sicurezza dell'intera classe dipende dall'implementazione di richiamata. Se ha stato mutevole, allora avrete potenziali problemi. Se richiamata è immutabile, allora avete thread-safe.

Callback otterrà un nuovo valore di ogni singola volta Foo () viene chiamato (anche dallo stesso filo). Io non sono molto sicuro di quello che il codice dovrebbe fare (se si desidera inizializzare la variabile statica solo una volta (Singleton), si dovrebbe verificare se è ancora nulla in getCallback () - e che cosa è actionCallback?). Per rendendolo thread-safe, utilizzare sincronizzata.

Credo che si ha sintetizzato perfettamente da soli, ma senza ulteriori dettagli su ciò che si sta tentando di raggiungere, sarà difficile da dare suggerimenti per risolvere il problema.

Una domanda ovvia è, non callback devono essere statica? Oppure si potrebbe tranquillamente farne un campo di istanza senza rompere la funzionalità della tua classe?

Lo so che è stato risposto, ma il motivo per cui non ha davvero stato dettagliato.

It due thread chiamano il metodo getCallback (), potrebbero eseguire le linee come segue:

  1. Thread 1 - callback = new Richiamata ();
  2. Discussione 2 - callback = new Richiamata ();
  3. Thread 1 - tornare actionCallback;
  4. Discussione 2 - tornare actionCallback;

In questo caso, il callback generata (2) vengono restituiti in entrambi (3) e (4).

La soluzione sembrerebbe essere quella di chiedere il motivo per cui callback definito staticly se è specifico per l'istanza non di classe.

Mi auguro che aiuta.

Che cosa si sta cercando di fare è chiamato un pattern Singleton, se si fa una ricerca si possono scoprire perché la sua generalmente una buona idea per evitare questo modello se è possibile, se ne avete bisogno potete fare quanto segue.

private static final Callback CALLBACK= new Callback();

Se avete bisogno di un Singleton pigri si può fare

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

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

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

Entrambe le implementazioni sono thread-safe.

Vuoi un callback per thread, uno per ogni oggetto, o un vero Singleton?

Alcuni schizzi su come fare le diverse varianti - solo dalla parte superiore della mia testa, non prendono questi troppo alla lettera:)

Si prega di notare che ho assunto che la richiamata ha un costruttore non banale che potrebbe gettare eccezione che deve essere gestita, se si tratta di un costruttore banale è possibile semplificare tutti questi molto.

Uno per filo:

  private static ThreadLocal<Callback> callback;

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

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

callback unico per tutte le discussioni:

  private final static Callback callback;

  static {
      callback = new Callback(); 
  }

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

  private static Callback getCallback()
  {
      return callback;
  }

E, per completezza, un callback per oggetto:

  private Callback callback;

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

  private Callback getCallback()
  {
      callback = new Callback();
      return callback;
  }
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top