Question

Je n'aime pas enfermer mon code avec synchronisé (ce) , donc je suis à expérimenter avec l'aide de AtomicBooleans . Dans l'extrait de code, XMPPConnectionIF.connect () fait une connexion de socket à un serveur distant. Notez que n'est jamais utilisé la variable _connecting connect () méthode ; tandis que _connected est utilisé dans toutes les autres méthodes qui a besoin d'utiliser le _xmppConn . Mes questions sont listés après l'extrait de code ci-dessous.

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. Sur la base de mon code, est-ce thread-safe au point que si 2 threads tentent d'appeler connect () en même temps, une seule tentative de connexion est autorisée.

  2. Dans le bloc finalement, je suis deux AtomicBoolean.set exécutais (..) en succession, sera là un problème, étant donné que lors de l'écart entre ces 2 appels atomiques, certains threads peuvent appeler _connected .get () dans d'autres méthodes?

  3. Lorsque vous utilisez _xmppConn , dois-je faire une synchronisé (_xmppConn)

UPDATE Ajout appel de connexion manquant dans la méthode.

Était-ce utile?

La solution

  1. Oui. La variable agit comme un verrou _connecting de test et de jeu qui empêche de multiples tentatives de connexion simultanées.

  2. Pas de problème -. Même si un autre thread lit _connected entre les écritures, _connecting va l'empêcher de tenter de se connecter en même temps

  3. Oui, en supposant que ses

    méthodes ne sont pas déjà thread-safe.

Cela étant dit, votre méthode de connexion () me rendre fou dans sa forme actuelle, car il ne se connecte pas nécessairement ou lancer une exception. Vous pouvez ajouter une boucle de spin, mais ce n'est pas vraiment un bon ajustement parce que pour tous, mais le houblon le plus court du réseau à partir d'une machine multiprocesseur, il sera plus efficace pour produire. Les primitives d'accès concurrentiel bas niveau, par ailleurs, sont beaucoup plus sujettes à l'erreur que synchronisée -. I fortement vous recommandons persévérez avec synchronisation

Autres conseils

Gardez à l'esprit que l'utilisation 3 AtomicBooleans est pas la même chose que garder ces trois variables avec une seule serrure. Il me semble que l'état de ces variables constitue un état unique de l'objet et donc qu'ils devraient être gardés par la même serrure. Dans votre code en utilisant des variables atomiques, il est possible pour les différents threads pour mettre à jour l'état de _connected, _connecting et _shuttingDown indépendamment - en utilisant des variables atomiques ne s'assurer que l'accès au même variable est synchronisé entre plusieurs threads .

Cela dit, je ne pense pas que la synchronisation sur le this est ce que vous voulez faire. Vous voulez seulement synchroniser l'accès à l'état de connexion. Ce que vous pouvez faire est de créer un objet à utiliser comme verrou pour cet état sans obtenir le moniteur 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.
  }
}

Si vous faites la programmation concurrente en Java, je recommande fortement la lecture Java Concurrency Dans pratique .

Je pense que d'autres couvrent la justesse de manière adéquate dans leurs commentaires. Mon seul commentaire supplémentaire serait que je suis préoccupé un peu au sujet de la mise en place de la libération dans le finalement. On dirait que vous pourriez vraiment vouloir envelopper tout le bloc là (y compris l'appel _xmppConnProvider.get ()) dans un try {} {} enfin qui garantirait vous toujours libérer le verrou. Dans le cas contraire, une sorte d'exception non contrôlée pourrait se produire là-bas et vous laisser dans un état irrécupérable.

Stylistiquement, je considère ce code comme beaucoup plus difficile à raisonner sur que d'utiliser simplement synchronisé / Lock pour obtenir l'exclusion mutuelle. Je commencerais avec le code qui est facile à raisonner sur et faire que plus compliqué si vous pouvez prouver que cela est un point chaud.

Je doute que votre programme sera thread-safe. Je ne suis pas gourou modèle Java mémoire, mais de ce que j'ai appris les opérations peuvent être organisées et les résultats d'exploitation peuvent ne pas être visibles à d'autres sujets dans l'ordre que vous attendez.

Prenons le cas par exemple de réglage _connected true est exécutée avant que la méthode de connexion () est entièrement exécuté? Un autre thread pourrait penser que vous êtes connecté, même si vous n'êtes pas. Ceci est juste conjecture -. Je ne sais pas ce problème particulier peut se produire à tout

Mon point est plutôt le genre de blocage que vous essayez de faire est extrêmement difficile à obtenir le droit. Stick avec synchronisé ou utiliser les verrous dans le paquet java.util.concurrent.locks .

  1. Oui sans aucun doute son satisfait. comme _connecting.compareAndSet (false, true) permettra un seul thread d'entrer.

  2. Vous ne devez définir _connected.set (false); comme il est jamais mis à true si exception a eu lieu. Oui il est possible non en raison de la succession, mais jusqu'à ce que vous avez pas encore se connecter à de faux autres threads essayant de se connecter ne sera pas fait de penser qu'une connexion est en cours.

  3. Oui si xmppConn est pas thread-safe.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top