Essa classe usa AtomicBooleans. É o segmento de seguros?
-
06-09-2019 - |
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 );
}
}
}
-
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.
-
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?
-
Ao usar _xmppConn , eu deveria fazer um sincronizado (_xmppConn) ?
Atualizar Adicionado faltando chamada de login para o método.
Solução
-
Sim. O _connecting variável actua como um bloqueio de ensaio-e-conjunto que impede que várias tentativas de ligação concorrente.
-
Não há problema -. Mesmo se outro thread lê _connected entre as gravações, _connecting vai impedi-lo de tentar conectar simultaneamente
-
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 AtomicBoolean
s é 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
-
Sim, é definitivamente satisfeito. como _connecting.compareAndSet (false, true) permitirá que apenas um segmento para entrar.
-
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.
-
Sim se xmppConn não é thread-safe.