2

每当我寻找并发访问时,我得到的答案是复杂的

我有 3 个线程。一个线程负责建立连接并创建一个单例连接对象实例。另外两个线程将不断地发送数据。

现在,其他线程将等待CountDownLatch连接线程一旦建立连接,连接线程将倒计时到零。

这是我在ConnectStatus类中声明的内容,希望connected变量同步并对所有线程可见。

public class ConnectStatus {

public static final CountDownLatch connectionLatch = new CountDownLatch(1);
private static volatile AtomicBoolean connected;

}

我正在使用这个connected易失且原子的变量来维护连接状态。这样其他线程就可以在发送数据之前“始终”知道连接是否处于活动状态。

一旦我建立了连接,我将把这个布尔值设为真并将锁存为零。

ConnectStatus.connected.set(true);
ConnectStatus.connectionLatch.countdown();

现在其他线程将收到锁存器的通知,原子值也将为真,线程开始发送数据。

在下面发送数据线程片段。

if(ConnectStatus.connected.get()){

   // send data

}

现在这是我的问题,连接可能随时变坏和断开,所以那个时候,我把我的原子设置connected为假的。我想知道的是,这个线程安全吗,我的其他线程总是会得到这个原子的、易失的变量的更新值吗?每当我的连接中断时,我需要我的另外两个线程停止发送数据。

if(ConnectStatus.connected.get()){

   // send data

}

上面的代码片段总是能正常工作吗?

4

2 回答 2

3

连接可能随时变坏和断开,所以那个时候,我把我的原子连接为假的。我想知道的是,这个线程安全吗,我的其他线程总是会得到这个原子的、易失的变量的更新值吗?

是和不是。首先,你AtomicBoolean应该是final不是 volatileAtomicBoolean包装 avolatile boolean但您不会将其更改为另一个AtomicBoolean

private static final AtomicBoolean connected = new AtomicBoolean(false);

仅使用 anAtomicBoolean来保护连接的问题是(如@Jeff 所述)即使您测试连接是否已连接,之后也可能会直接断开连接。

if (ConnectStatus.connected.get()) {
   // disconnect happens here, before the send
   // send data
}

您无法使用AtomicBoolean. 您需要有一个锁,以便断开连接的线程等待所有发送完成:

private final Object lock = new Object();
...
synchronized (lock) {
   if (connected) {
      sendData();
   }
}
...
// this has to wait for the lock to be released before it can be closed
synchronized (lock) {
   if (connected) {
      disconnect();
      connected = false;
   }
}

如果您无法控制连接断开的时间,那么您将必须正确捕获异常并适当地处理它们。

最后,如果您需要多个发件人,那么您应该查看 aReentrantReadWriteLock并将您的发件人锁定为一次允许多个读者的“读者”(有趣),并将关闭线程锁定为仅允许一个作者的“作者”一次。

于 2013-09-19T21:12:15.863 回答
2

volatile确保可见性,因此如果connected变量由一个线程更新,它将在另一个线程中可见。但是,正如@Gray 在他的评论中指出的那样,这并不是你正在做的事情。AtomicBoolean如果您不进行原子比较和设置操作,则不需要使用。如果您只是阅读或编写 a boolean,那就是原子http://docs.oracle.com/javase/tutorial/essential/concurrency/atomic.html。但是,您仍然有竞争条件。如果在检查 的get状态后connected,连接断开怎么办?

于 2013-09-19T21:06:08.437 回答