I don’t like to lock up my code with synchronized(this), so I’m experimenting with using AtomicBooleans. In the code snippet, XMPPConnectionIF.connect() makes a socket connection to a remote server. Note that the variable _connecting is only ever used in the connect() method; whereas _connected is used in every other methods that needs to use the _xmppConn. My questions are listed after the code snippet below.
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 );
}
}
}
-
Based on my code, is it thread safe to the point that if 2 threads attempt to call connect() at the same time, only one connection attempt is allowed.
-
In the finally block, I am executing two AtomicBoolean.set(..) in succession, will be there be a problem, since during the gap between these 2 atomic calls, some threads might call _connected.get() in other methods ?
-
When using _xmppConn, should I do a synchronized( _xmppConn ) ?
UPDATE Added missing login call into the method.
Yes. The variable _connecting acts as a test-and-set lock that prevents multiple concurrent connection attempts.
No problem — even if another thread reads _connected between the writes, _connecting will prevent it from attempting to connect concurrently.
Yes, assuming that its methods are not already thread-safe.
That being said, your connect() method would drive me nuts in its current form, since it doesn’t necessarily connect or throw an exception. You could add a spin loop, but that’s not really a good fit because for all but the shortest of network hops from a multiprocessor machine, it will be more efficient to yield. The low-level concurrency primitives, moreover, are a lot more error-prone than synchronized — I strongly recommend you stick with synchronized.