Pregunta

No me gusta encerrar a mi código con sincronizado (este) , por lo que estoy experimentando con el uso de AtomicBooleans . En el fragmento de código, XMPPConnectionIF.connect () hace una conexión de socket a un servidor remoto. Tenga en cuenta que la variable _connecting sólo se utiliza nunca en el connect () método; mientras que _connected se utiliza en todos los otros métodos que necesita usar el _xmppConn . Mis preguntas se enumeran después de que el fragmento de código a continuación.

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. Sobre la base de mi código, ¿es hilo de seguridad hasta el punto de que si 2 hilos intentan llamar connect () al mismo tiempo, sólo se permite un intento de conexión.

  2. En el bloque finally, Estoy ejecutando dos AtomicBoolean.set (..) en la serie, estará allí ser un problema, ya que durante la brecha entre estos 2 llamadas atómicas, algunos temas podrían llamar _connected .get () en otros métodos?

  3. Cuando se utiliza _xmppConn , debo hacer un sincronizada (_xmppConn)

Actualizar Añadido llamada de inicio de sesión que falta en el método.

¿Fue útil?

Solución

  1. Sí. Los _connecting variables actúa como un bloqueo de prueba-y-conjunto que previene múltiples intentos de conexión concurrente.

  2. No hay problema -. Incluso si otro hilo lee _connected entre las escrituras, _connecting evitará que intentar conectar simultáneamente

  3. Sí, suponiendo que sus métodos no son ya thread-safe.

Una vez dicho esto, el método connect () sería me vuelven loco en su forma actual, ya que no necesariamente conecte o una excepción. Se podría añadir un bucle de vuelta, pero eso no es realmente una buena opción, porque para todos, pero el más corto de saltos de red de una máquina multiprocesador, será más eficiente para producir. Las primitivas de concurrencia de bajo nivel, por otra parte, son mucho más propensos a errores que sincroniza -. I muy recomiendo que empiece con sincronizada

Otros consejos

Tenga en cuenta que el uso de 3 AtomicBooleans es no lo mismo que guarda esas tres variables con un candado. Me parece como el estado de las variables constituye un único estado del objeto y por lo tanto que deben ser vigilados por la misma cerradura. En su código usando las variables atómicas, es posible que los diferentes hilos para actualizar el estado de _connected, _connecting y _shuttingDown independiente - el uso de variables atómicas sólo se asegurará de que el acceso a la mismo variables se sincroniza entre varios subprocesos .

Dicho esto, no creo que la sincronización en la this es lo que quiere hacer. Sólo desea sincronizar el acceso al estado de conexión. Lo que podría hacer es crear un objeto de usar como el bloqueo de este estado sin que el monitor en this. A saber:

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 estás haciendo la programación concurrente en Java, lo recomiendo encarecidamente leer Java concurrencia en practicar .

Creo que los demás están cubriendo la corrección adecuada en sus comentarios. Mi único comentario adicional sería que a mí respecta un poco acerca de la colocación de la liberación en el fin. Parece que es posible que realmente desee para envolver todo el bloque (lo que incluye la llamada _xmppConnProvider.get ()) en un try {} {} finalmente que garantizaría que siempre sería liberar el bloqueo. De lo contrario, algún tipo de excepción no comprobada podría suceder allí y le dejará en un estado irrecuperable.

Estilísticamente, considero que este código como mucho más difícil de razonar acerca de que el simple uso sincronizado / bloqueo para lograr la exclusión mutua. Me gustaría empezar con código que es fácil de razonar acerca y sólo hacerlo más complicado si se puede demostrar que este es un punto caliente.

Dudo su programa será seguro para subprocesos. No soy un gurú de Java modelo de memoria, pero por lo que he aprendido operaciones se pueden organizar y resultados de operación pueden no ser visibles para los otros hilos en el orden que usted espera.

Tenga en cuenta que si por ejemplo el ajuste de _connected a true se ejecuta antes de que el método connect () sea ejecutada por completo? Otro hilo podría pensar que usted está conectado a pesar de que no lo son. Esto es sólo una conjetura -. No estoy seguro de que determinado problema puede ocurrir en absoluto

Mi punto es más bien que el tipo de bloqueo que está tratando de hacer es extremadamente difícil de conseguir derecha. Stick con sincronizado o utilizar las cerraduras en el paquete java.util.concurrent.locks.

  1. Sí, es sin duda satisfecho. como _connecting.compareAndSet (false, true) permitirá sólo un hilo para entrar.

  2. Usted no necesita configurar _connected.set (false); ya que nunca se establece en true si ocurrió una excepción. Sí, es posible, no se debe a la sucesión, pero hasta que no se haya configurado la conexión a otros hilos falsas que intentan conectarse no será hacer pensar que una conexión está en curso.

  3. Sí si xmppConn no es seguro para subprocesos.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top