Domanda

Non mi piace per bloccare il mio codice con synchronized(this), così sto sperimentando con l'utilizzo di AtomicBooleans.Nel frammento di codice, XMPPConnectionIF.connect() fa un socket di connessione a un server remoto.Si noti che la variabile _connecting è sempre e solo utilizzato nel connect() metodo;considerando che _connected viene utilizzato in tutti gli altri metodi che devono utilizzare il _xmppConn.Le mie domande sono elencati dopo il frammento di codice qui di seguito.

private final AtomicBoolean _connecting = new AtomicBoolean( false );
private final AtomicBoolean _connected = new AtomicBoolean( false ); 
private final AtomicBoolean _shuttingDown = new AtomicBoolean( false ); 
private XMPPConnection _xmppConn;
/**
 * @throws XMPPFault if failed to connect
 */
public void connect() 
{
    // 1) you can only connect once
    if( _connected.get() )
        return;

    // 2) if we're in the middle of completing a connection, 
    //    you're out of luck
    if( _connecting.compareAndSet( false, true ) )
    {
        XMPPConnectionIF aXmppConnection = _xmppConnProvider.get();
        boolean encounteredFault = false;

        try
        {
            aXmppConnection.connect(); // may throw XMPPException
            aXmppConnection.login( "user", "password" ); // may throw XMPPException
            _connected.compareAndSet( false, true );
            _xmppConn = aXmppConnection;
        }
        catch( XMPPException xmppe )
        {
            encounteredFault = true;
            throw new XMPPFault( "failed due to", xmppe );
        }
        finally
        {
            if( encounteredFault )
            {
                _connected.set( false );
                _connecting.set( false );
            }
            else
                _connecting.compareAndSet( true, false );
        }
    }
}
  1. Basato sul mio codice, è thread-safe, al punto che se 2 thread tenta di chiamare connect() allo stesso tempo, solo un tentativo di connessione è consentito.

  2. Nel blocco finally, io sono l'esecuzione di due AtomicBoolean.set(..) in successione, ci sarà essere un problema, dal momento che il divario fra le 2 atomiche chiamate, alcuni thread potrebbe chiamare _connected.get() in altri metodi ?

  3. Quando si utilizza _xmppConn, devo fare un sincronizzati( _xmppConn ) ?

AGGIORNAMENTO Aggiunto mancanti login chiamata al metodo.

È stato utile?

Soluzione

  1. Sì.La variabile _connecting agisce come un test-and-set di blocco che impedisce concorrenti più tentativi di connessione.

  2. Nessun problema, anche se un altro thread legge _connected tra le scrive, _connecting impedirà di tentare di collegare contemporaneamente.

  3. Sì, assumendo che i suoi metodi non sono già thread-safe.

Detto questo, il metodo connect() mi portava, noci, nella sua forma attuale, dal momento che non necessariamente collegare o lanciare un'eccezione.Si potrebbe aggiungere un giro di loop, ma che non è davvero una buona forma, perché per tutti, ma il più breve di rete luppolo da una macchina multiprocessore, sarà più efficiente per produrre.Il basso livello di concorrenza primitive, inoltre, sono molto più inclini all'errore di sincronizzato -- io fortemente consiglia di attaccare con sincronizzati.

Altri suggerimenti

Tieni presente che l'utilizzo di 3 AtomicBooleans è non la stessa guardia quei tre variabili con un singolo blocco. Mi sembra come lo stato di queste variabili costituisce un unico stato dell'oggetto e quindi che essi dovrebbero essere custoditi dalla stessa serratura. Nel codice utilizzando variabili atomiche, è possibile per diversi thread per aggiornare lo stato di _connected, _connecting e _shuttingDown indipendentemente - utilizzo di variabili atomiche solo garantire che l'accesso al stesso variabile è sincronizzato tra più thread .

Detto questo, non credo che la sincronizzazione sul this è ciò che si vuole fare. Si desidera solo per sincronizzare l'accesso allo stato di connessione. Che cosa si potrebbe fare è creare un oggetto da utilizzare come il blocco di questo stato senza ottenere il monitor this. Viz:

class Thing {
  Boolean connected;
  Boolean connecting;
  Boolean shuttingDown;
  Object connectionStateLock = new Object();

  void connect() {
    synchronized (connectionStateLock) {
      // do something with the connection state.
    }
  }

  void someOtherMethodThatLeavesConnectionStateAlone() {
    // free range thing-doing, without getting a lock on anything.
  }
}

Se stai facendo programmazione concorrente in Java, vi consiglio vivamente la lettura di Java Concurrency In Pratica .

Credo che gli altri stanno coprendo adeguatamente correttezza nei loro commenti. Il mio unico commento ulteriore sarebbe che mi riguarda un po 'circa la collocazione del rilascio in finally. Sembra che si potrebbe davvero desiderare di avvolgere l'intero blocco lì (tra cui la chiamata _xmppConnProvider.get ()) in un try {} {} infine che garantisse si sarebbe sempre rilasciare il blocco. In caso contrario, una sorta di eccezione incontrollato potrebbe accadere in là e si lascia in uno stato irreversibile.

Stilisticamente, considero questo codice come molto più difficile ragionare su che semplicemente utilizzando sincronizzato / Blocco per realizzare la mutua esclusione. Vorrei iniziare con il codice che è facile da ragionare su e solo renderlo più complicato se si può dimostrare che questo è un punto caldo.

Dubito il programma sarà thread-safe. Io non sono Java Memory Model guru, ma da quello che ho imparato le operazioni possono essere organizzati e risultati delle operazioni potrebbero non essere visibili ad altri thread nell'ordine che ci si aspetta.

Si consideri, ad esempio, se l'impostazione _connected a true viene eseguito prima che il metodo connect () è completamente eseguita? Un altro thread potrebbe pensare che si è connessi, anche se non lo sono. Questa è solo una congettura -. Non sono sicuro che il particolare problema può verificarsi a tutti

Il mio punto è piuttosto che il tipo di blocco che si sta tentando di fare è estremamente difficile da ottenere. Stick con sincronizzato o utilizzare le serrature nel java.util.concurrent.locks pacchetto.

  1. Sì, è decisamente soddisfatti. come _connecting.compareAndSet (false, true) consente solo un thread per entrare.

  2. Non avete bisogno di impostare _connected.set (false); come non è mai impostata su true se un'eccezione è accaduto. Sì, è possibile, non a causa di successione, ma fino a che non è stato impostato il collegamento a falsi altri thread che cercano di connettersi non sarà facendo pensare che una connessione è in corso.

  3. Sì se xmppConn non è thread-safe.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top