我什么时候需要在Java中使用AtomicBoolean?

yar*_*art 214 java concurrency

我如何使用AtomicBoolean以及该类的用途是什么?

Boz*_*zho 226

当多个线程需要检查并更改布尔值时.例如:

if (!initialized) {
   initialize();
   initialized = true;
}
Run Code Online (Sandbox Code Playgroud)

这不是线程安全的.您可以使用AtomicBoolean以下方法修复它:

if (atomicInitialized.compareAndSet(false, true)) {
    initialize();
}
Run Code Online (Sandbox Code Playgroud)

  • 它看起来不像是一个真实世界的例子 - 当`initialize()`尚未完成时,其他线程可以看到`true`.因此,只有当其他线程不关心`initialize()`的完成时,它才有效. (46认同)
  • 你需要2个booleans用于initStarted和initCompleted,然后第一个线程设置initStarted并调用initialise(),其余的等待直到initCompleted为真. (14认同)
  • @axtavt:我认为这是一个完全有效的现实世界的例子,如果`initialized`只是用来确保一个且只有一个线程将调用`initialize()`方法.显然`initialized`为true并不意味着在这种情况下初始化已经完成,所以_maybe_稍微不同的术语在这里会更好.同样,这取决于它的用途. (6认同)
  • @Bozho - 读取和写入*boolean*字段是原子对吗?现在,*volatile*给出了布尔字段的最新值.所以,实际上,`volatile boolean`不会与`AtomicBoolean`相同吗? (2认同)
  • @TheLostMind 我参加聚会已经很晚了,但是您会错过诸如“compareAndSet”之类的功能,如果没有某种同步,它们实际上无法实现 (2认同)
  • @Martin:没有直接的方法可以等待布尔值变为真;你需要额外的机制。最明智的方法是使用“同步”块,在这种情况下,您不再需要“AtomicBoolean”,只需要“volatile boolean”。(`if(!this.initialized) { synchronized(this) { if(!this.initialized) { initialize(); this.initialized = true; } } }` 将确保只有一个线程调用 `initialize`,并且所有其他线程等待它完成,前提是 `initialized` 被标记为 `volatile`。) (2认同)

Ara*_*ram 50

以下是我所做的笔记(来自Brian Goetz的书)可能对你有所帮助

AtomicXXX课程

  • 提供无阻塞比较和交换实现

  • 利用硬件提供的支持(英特尔的CMPXCHG指令)当许多线程运行使用这些原子并发API的代码时,它们将比使用对象级监视器/同步的代码更好地扩展.因为,Java的同步机制使代码等待,当有许多线程在关键部分运行时,花费大量的CPU时间来管理同步机制本身(等待,通知等).由于新API使用硬件级别构造(原子变量)和等待和锁定自由算法来实现线程安全性,因此花费更多的CPU时间来"做事"而不是管理同步.

  • 不仅提供更好的吞吐量,而且它们还提供更强的抵抗活动问题,如死锁和优先级倒置.

  • 您能详细说明如何非阻塞地访问 AtomicXXX 吗?谢谢 (3认同)

Joh*_*int 34

有两个主要原因可以使用原子布尔值.首先它是可变的,你可以将它作为引用传递,并改变与布尔本身相关联的值,例如.

public final class MyThreadSafeClass{

    private AtomicBoolean myBoolean = new AtomicBoolean(false);
    private SomeThreadSafeObject someObject = new SomeThreadSafeObject();

    public boolean doSomething(){
         someObject.doSomeWork(myBoolean);
         return myBoolean.get(); //will return true
    }
}
Run Code Online (Sandbox Code Playgroud)

并在someObject类中

public final class SomeThreadSafeObject{
    public void doSomeWork(AtomicBoolean b){
        b.set(true);
    }
}
Run Code Online (Sandbox Code Playgroud)

更重要的是,它的线程安全并且可以向维护该类的开发人员指出,该变量应该被修改并从多个线程读取.如果不使用AtomicBoolean,则必须通过声明volatile或在字段的读写周围进行同步来同步您正在使用的布尔变量.

  • 对于上帝的爱,这只是为了表明物体本身的可变性.我特意写了这个用于演示目的. (4认同)
  • 现在更好的例子:) (2认同)
  • 我认为只有 Volatile 是不够的。考虑一下这样的情况:两个线程直接从主内存读取和写入相同的值,这些线程之间没有任何同步 - 可能会出现并发问题。 (2认同)

Cam*_*ner 18

AtomicBoolean班给你,你可以原子更新一个布尔值.当多个线程访问布尔变量时使用它.

java.util.concurrent.atomic包概述给你的东西在这个包中的类做和何时使用它们好高层次的描述.我还推荐Brian Goetz 撰写的Java Concurrency in Practice一书.


Osc*_*Ryz 5

摘自包装说明

包java.util.concurrent.atomic description:一个小型的工具包,支持对单个变量进行无锁线程安全编程.[...]

这些方法的规范使实现能够采用当代处理器上可用的高效机器级原子指令.[...]

类AtomicBoolean,AtomicInteger,AtomicLong和AtomicReference的实例都提供对相应类型的单个变量的访问和更新.[...]

访问和更新原子的记忆效应通常遵循挥发物的规则:

  • get具有读取volatile变量的记忆效应.
  • set具有写入(赋值)volatile变量的记忆效应.
  • weakCompareAndSet以原子方式读取并有条件地写入变量,相对于该变量上的其他内存操作进行排序,但另外作为普通的非易失性存储器操作.
  • compareAndSet和所有其他读取和更新操作(如getAndIncrement)都具有读取和写入volatile变量的内存效果.