【问题标题】:Will the use of volatile & atomic always ensures thread safety使用 volatile 和 atomic 是否总能确保线程安全
【发布时间】:2013-09-25 03:04:26
【问题描述】:

每当我寻找并发访问时,我都会得到不同的答案,我已经订购了 JCIP 书籍并且正在路上,但我想确定我的并发基础知识,这是我的场景

我有 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();

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

下面发送数据线程sn-p。

if(ConnectStatus.connected.get()){

   // send data

}

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

if(ConnectStatus.connected.get()){

   // send data

}

上面的sn-p会一直正常工作吗?

【问题讨论】:

  • 使用 volatile & atomic 是否总能保证线程安全?不,并非总是如此。
  • 您的AtomicBoolean 应该是final不是 volatileAtomicBoolean 包装了 volatile boolean,但您不会将其更改为另一个 AtomicBooleanvolatile 不保护对象的内容,它只是引用。
  • 您总是遇到发送中途断开连接的问题,这无济于事。使用现有的众多连接池库之一是否存在问题?即使您的池大小为 1,它们也会处理线程问题。
  • +1 表示 volatile 不保护对象的内容,它只是引用。

标签: java multithreading concurrency thread-safety java.util.concurrent


【解决方案1】:

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

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

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

仅使用AtomicBoolean 保护连接的问题是(如@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;
   }
}

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

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

【讨论】:

    【解决方案2】:

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

    【讨论】:

      猜你喜欢
      • 2017-03-15
      • 1970-01-01
      • 1970-01-01
      • 2016-10-28
      • 1970-01-01
      • 1970-01-01
      • 2017-10-18
      • 1970-01-01
      • 2013-03-01
      相关资源
      最近更新 更多