Pergunta

Eu não gosto de trancar o meu código com sincronizado (this) , então eu estou experimentando com o uso de AtomicBooleans . No trecho de código, XMPPConnectionIF.connect () faz uma conexão de soquete para um servidor remoto. Note-se que a variável _connecting é sempre apenas usado no connect () método; enquanto _connected é usado em todos os outros métodos que as necessidades de usar o _xmppConn . Minhas perguntas são listados após o trecho de código abaixo.

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. Com base no meu código, que é o segmento de seguros, a ponto de se 2 fios tentativa de chamar connect () , ao mesmo tempo, apenas uma tentativa de conexão é permitido.

  2. Nos dois AtomicBoolean.set bloco finally, eu estou executando (..) em sucessão, vai estar lá ser um problema, uma vez que durante a lacuna entre estes 2 chamadas atômicas, alguns segmentos podem chamar _connected .get () em outros métodos?

  3. Ao usar _xmppConn , eu deveria fazer um sincronizado (_xmppConn) ?

Atualizar Adicionado faltando chamada de login para o método.

Foi útil?

Solução

  1. Sim. O _connecting variável actua como um bloqueio de ensaio-e-conjunto que impede que várias tentativas de ligação concorrente.

  2. Não há problema -. Mesmo se outro thread lê _connected entre as gravações, _connecting vai impedi-lo de tentar conectar simultaneamente

  3. Sim, assumindo que seus métodos não são já thread-safe.

Dito isto, o método connect () iria conduzir-me louco na sua forma actual, uma vez que não necessariamente conexão ou lançar uma exceção. Você pode adicionar um loop de rotação, mas isso não é realmente uma boa opção porque para todos, mas o menor de saltos de rede de uma máquina multiprocessador, será mais eficiente para produzir. As primitivas de baixo nível de concorrência, por outro lado, são muito mais propenso a erros do que sincronizada - I fortemente recomendamos que você ficar com sincronizados

.

Outras dicas

Tenha em mente que o uso de 3 AtomicBooleans é não o mesmo que guardar essas três variáveis ??com um único bloqueio. Parece-me que o estado dessas variáveis ??constitui um único estado do objeto e, portanto, que deve ser guardado pelo mesmo bloqueio. Em seu código usando variáveis ??atômicas, é possível para diferentes tópicos para atualizar o estado de _connected, _connecting e _shuttingDown independente - usando variáveis ??atômicas só irá garantir que o acesso ao mesma variável é sincronizado entre vários segmentos .

Dito isso, eu não acho que a sincronização na this é o que você quer fazer. Você só quer sincronizar o acesso para o estado da conexão. O que você poderia fazer é criar um objeto para uso como o bloqueio para esse estado sem obter o 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 você está fazendo programação concorrente em Java, eu recomendo a leitura Java simultaneidade em praticar .

Eu acho que os outros estão cobrindo correção adequadamente nas suas observações. Meu único comentário adicional seria que eu estou preocupado um pouco sobre a colocação do lançamento no finalmente. Parece que você pode realmente quer envolver todo o bloco lá (incluindo a chamada _xmppConnProvider.get ()) em um try {} finally {} que garantiria você sempre liberar o bloqueio. Caso contrário, algum tipo de exceção não verificada poderia acontecer lá e deixá-lo em um estado irrecuperável.

Estilisticamente, eu considero esse código como muito mais difícil raciocinar sobre o que simplesmente usando sincronizado / Bloqueio para alcançar a exclusão mútua. Gostaria de começar com o código que é fácil raciocinar sobre e apenas torná-lo mais complicado se você puder provar que este é um hot spot.

Eu duvido que seu programa vai ser thread-safe. Eu não sou nenhum guru Java Memory Model, mas pelo que eu aprendi operações podem ser organizadas e os resultados das operações podem não ser visíveis a outros tópicos na ordem que você espera.

Considere se, por exemplo configuração _connected a verdade é executado antes que o método connect () é totalmente executado? Outro segmento poderia pensar que você está conectado, mesmo que você não é. Este é apenas conjectura -. Não estou certo de que determinado problema pode ocorrer em tudo

Meu ponto é, sim, que o tipo de bloqueio que você está tentando fazer é extremamente complicado de acertar. Vara com sincronizado ou usar as fechaduras no java.util.concurrent.locks pacote.

  1. Sim, é definitivamente satisfeito. como _connecting.compareAndSet (false, true) permitirá que apenas um segmento para entrar.

  2. Você não precisa _connected.set set (false); como nunca é definido como verdadeiro se a exceção aconteceu. Sim é possível, não devido à sucessão, mas até você não tiver configurado a conexão com falsos outros Threads tentando se conectar não vai estar fazendo pensar que uma conexão está em andamento.

  3. Sim se xmppConn não é thread-safe.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top