Frage

Ich habe nicht meinen Code wie mit einzusperren synchronisiert (this) , so dass ich dem Experimentieren mit der Verwendung von AtomicBooleans . Im Code-Schnipsel, XMPPConnectionIF.connect () macht eine Socket-Verbindung zu einem Remote-Server. Beachten Sie, dass die Variable _connecting wird immer nur verwendet in der connect () Methode; während _connected in allen anderen Methoden verwendet, die die _xmppConn verwenden muss. Meine Fragen sind aufgelistet nach dem folgenden Code-Snippet.

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. Basierend auf meinem Code ist es auf den Punkt Thread-sicher, dass, wenn zwei Threads zu nennen versuchen, connect () zur gleichen Zeit, nur ein Verbindungsversuch erlaubt ist.

  2. In der finally-Block, ich bin Ausführung zwei AtomicBoolean.set (..) in Folge, wird es ein Problem sein, da während der Lücke zwischen diesen zwei Atom-Gespräche könnten einige Threads rufen _connected .get () in anderen Methoden?

  3. Bei der Verwendung von _xmppConn , soll ich tun, eine synchronisiert (_xmppConn)

UPDATE hinzugefügt fehlender Login Aufruf an die Methode.

War es hilfreich?

Lösung

  1. Ja. Die variablen _connecting wirkt als Test-and-set Sperre, die mehrere gleichzeitige Verbindungsversuche verhindert.

  2. Kein Problem -. Auch wenn ein anderer Thread zwischen dem Schreib _connected liest, _connecting wird verhindern, dass es versucht, gleichzeitig zu verbinden

  3. Ja, unter der Annahme, dass seine Methoden nicht bereits Thread-sicher.

aber sagt, dass Ihre Methode connect () würde mich verrückt in seiner jetzigen Form fahren, da es nicht unbedingt eine Verbindung oder eine Ausnahme werfen. Sie könnten eine Spinschleife hinzufügen, aber das ist nicht wirklich eine gute Passform, weil für alle, aber die kürzeste Netzwerk von einer Multi-Prozessor-Maschine Hopfen, wird es effizienter sein, zu erhalten. Die Low-Level-Parallelität Primitiven sind zudem viel fehleranfälliger als synchronisiert -. I stark empfehlen Sie synchronisiert halten

Andere Tipps

Beachten Sie, dass 3 AtomicBooleans verwendet, ist nicht die gleiche wie diese drei Variablen mit einem einzigen Schloss bewachten. Es scheint mir, wie der Zustand dieser Variablen einen einzigen Zustand des Objekts darstellt und damit, dass sie von der gleichen Sperre geschützt werden sollen. In Ihrem Code mit Atom-Variablen ist es möglich, für verschiedene Themen, die den Zustand von _connected, _connecting und _shuttingDown unabhängig zu aktualisieren - Atom-Variablen werden sichergestellt, nur dass der Zugriff auf den gleiche Variable zwischen mehreren Threads synchronisiert .

Das heißt, ich glaube nicht, auf der this Synchronisierung ist, was Sie tun wollen. Sie wollen nur den Zugang zu dem Verbindungszustand synchronisieren. Was Sie tun können, ist ein Objekt erstellen, die als Sperre für diesen Zustand zu verwenden, ohne den Monitor auf this zu bekommen. 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.
  }
}

Wenn Sie die gleichzeitige Programmierung in Java tun, würde ich empfehlen Java Concurrency Beim Lesen üben Sie .

Ich glaube, andere decken Richtigkeit angemessen in ihren Kommentaren. Mein einziger zusätzlicher Kommentar wäre, dass ich ein wenig über die Platzierung der Veröffentlichung in der schließlich bin besorgt. Scheint, als ob Sie wirklich dort den ganzen Block wickeln möchten (einschließlich der _xmppConnProvider.get () -Aufruf) in einem try {} finally {}, dass Sie immer die Sperre freigeben würden garantieren würde. Andernfalls könnte eine Art ungeprüfter Ausnahme dort passieren und Sie in einem nicht behebbar Zustand verlassen.

Stilistisch halte ich diesen Code so viel schwieriger zu Grunde über, als nur mit synchronisierten / sperren gegenseitigen Ausschluß zu erreichen. Ich würde mit dem Code beginnen, der leicht zur Vernunft über und nur macht es noch komplizierter, wenn Sie nachweisen können, dass dies ein Hot Spot.

Ich bezweifle, Ihr Programm Thread-sicher sein. Ich bin kein Java Memory Model-Guru, aber von dem, was ich habe gelernt, Operationen angeordnet werden können und die Ergebnisse der Operationen können nicht zu anderen Threads in der Reihenfolge, die Sie erwarten zu sehen sein.

überlegen Sie, ob zum Beispiel Einstellung _connected auf true vor dem connect () -Methode ausgeführt wird, vollständig ausgeführt? Ein anderer Thread könnte denken, dass Sie verbunden sind, auch wenn Sie nicht sind. Dies ist nur eine Vermutung. - Ich bin nicht sicher, dass besonderes Problem überhaupt auftreten kann,

Mein Punkt ist vielmehr, dass die Art von Verriegelungs Sie extrem schwierig zu tun versuchen, ist richtig zu machen. Stick mit synchronisierten oder verwenden Sie die Sperren in dem java.util.concurrent.locks Paket.

  1. Ja, es ist auf jeden Fall zufrieden. wie _connecting.compareAndSet (false, true) kann nur einen Thread in erhalten.

  2. Sie brauchen nicht _connected.set (false) einzustellen; wie es nie auf true gesetzt, wenn Ausnahme passiert ist. Ja, es ist möglich, nicht aufgrund hintereinander, aber bis Sie nicht auf falsche anderen Threads Verbindungssatz versucht wird nicht verbinden sein Denken zu tun, dass eine Verbindung besteht.

  3. Ja, wenn xmppConn ist nicht Thread-sicher.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top