本课程使用AtomicBooleans.它是线程安全的吗?

Jac*_*ine 2 java concurrency multithreading xmpp smack

我不喜欢用synchronized(this)锁定我的代码,所以我正在尝试使用AtomicBooleans.在代码片段中,XMPPConnectionIF.connect()与远程服务器建立套接字连接.请注意,变量_connecting仅在connect()方法中使用; 而_connected用于需要使用_xmppConn的其他所有方法.我的问题列在下面的代码段之后.

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 );
        }
    }
}
Run Code Online (Sandbox Code Playgroud)
  1. 根据我的代码,如果2个线程同时尝试调用connect(),那么它是否是线程安全的,只允许一次连接尝试.

  2. 在finally块中,我连续执行两个AtomicBoolean.set(..),会出现问题,因为在这两个原子调用之间的间隙中,某些线程可能在其他方法中调用_connected.get()

  3. 使用_xmppConn时,我应该进行同步(_xmppConn)吗?

更新在方法中添加了缺少的登录调用.

Pau*_*rie 6

请记住,使用3 AtomicBooleans是一样的守着这三个变量与单个锁.在我看来,这些变量的状态构成了对象的单个状态,因此它们应该被同一个锁保护.在使用原子变量的代码,有可能为不同的线程更新的状态_connected,_connecting_shuttingDown独立-用原子变量只能保证访问相同的变量是多个线程之间的同步.

也就是说,我不认为同步this就是你想做的事情.您只想同步访问连接状态.你可以做的是创建一个对象,用作此状态的锁,而无需启用监视器this.即:

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.
  }
}
Run Code Online (Sandbox Code Playgroud)

如果您正在使用Java进行并发编程,我强烈建议您阅读Java Concurrency In Practice.


Dav*_*ave 5

  1. 是.变量_connecting充当测试和设置锁,可防止多个并发连接尝试.

  2. 没问题 - 即使另一个线程在写入之间读取_connected,_connecting也会阻止它尝试同时连接.

  3. 是的,假设它的方法不是线程安全的.

话虽这么说,你的connect()方法会以当前形式驱使我疯狂,因为它不一定连接或抛出异常.你可以添加一个旋转循环,但这并不是一个很好的选择,因为除了多处理器机器中最短的网络跳跃之外,它的产生效率会更高.此外,低级并发原语比同步更容易出错 - 我强烈建议你坚持使用synchronized.