如何在多线程环境中交换布尔值?

时间:2018-02-14 15:24:38

标签: java multithreading

1

volatile boolean bool = false;
// ...
bool = !bool;

2

volatile AtomicBoolean bool= new AtomicBoolean(false);
// ...
bool.set(!bool.get());

如果有多个线程正在运行,并且其中一个线程需要交换bool的值并使新值对其他线程可见,那么这两种方法是否存在允许另一个线程操作的相同问题发生在读取和写入之间,或AtomicBoolean确保在调用.get().set()之间不会发生任何事情?

4 个答案:

答案 0 :(得分:4)

AtomicBoolean无法确保get()set()之间不会发生任何事情。
您可以创建3个在同一对象上同步的方法get()set()swap()

您可以尝试这样的事情:

public class SyncBoolean
{
  public SyncBoolean()
  {
    value = false;
  }

  public synchronized boolean get()
  {
    return (value);
  }

  public synchronized void set(boolean newValue)
  {
    value = newValue;
  }

  public synchronized void swap()
  {
    value = !value;
  }

  private boolean value;

} // class SyncBoolean

答案 1 :(得分:3)

由于您提供的原因,两个版本都可能失败。一种选择是:

boolean b;
do {
  b = bool.get();
} while (! bool.compareAndSet(b, !b));

答案 2 :(得分:1)

bool = !boolbool.set(!bool.get())都不是原子的。将操作包装到synchronized块会有所帮助,因为两个线程无法在同一对象上输入两次。

synchronized(this) {
    bool.set(!bool.get());
}

答案 3 :(得分:1)

正如已经提到的,你不能简单地在一行中使用volatile boolean或AtomicBoolean来交换值。

有两种方法可以做到,上面也有说明:

  • 使用一个“全局”锁定/同步
  • via while循环和AtomicBoolean.compareAndSet

虽然第一个解决方案看起来更容易并且正常工作,但在我看来,在大多数情况下,它会被认为是一种不好的做法,应该避免。除非您对多个线程对此字段的同步修改计数非常高,否则第二个解决方案应该优于第一个解决方案。

尽管如此,如果你真的喜欢简单,并且不需要知道这个决定成本的更好表现,那就选择第一个。

要添加我的贡献,我注意到您已将原子变量定义为volatile,并且,以防万一,警告您,如果您不重新分配此字段,则可以将其{{1} },最好这样做finalfinal仅适用于实际字段值,如果您不更改它(您没有使用volatile的{​​{1}}方法)并且您已确定,其他线程将会看到初始化值(set/compareAndSet就可以了)使用它没有多大意义。