AtomicBoolean 是否保证“安全线程”?

Qk *_*ita 3 java multithreading atomic

根据我在互联网上阅读的一些文档,Atomic 类的变量如AtomicInteger, AtomicLong,... 只允许 1 个线程同时访问它们。但是当我尝试使用 进行测试时AtomicBoolean,出了点问题。例如

public class TestAtomicBoolean {
    public static void main(String[] args) {
        final AtomicBoolean atomicBoolean = new AtomicBoolean(false);

        new Thread("T1") {
            @Override
            public void run() {
                while (true) {
                    System.out.println(Thread.currentThread().getName() + " is waiting for T3 set Atomic to true. Current is " + atomicBoolean.get());
                    if (atomicBoolean.compareAndSet(true, false)) {                        
                        System.out.println("Done. Atomic now is " + atomicBoolean.get());
                        break;
                    }                    
                }
            }
        }.start();

        new Thread("T2") {
            @Override
            public void run() {
                while(true) {
                    System.out.println(Thread.currentThread().getName() + " " + atomicBoolean.get());                    
                }               
            }           
        }.start();

        new Thread("T3") {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName() + " " + atomicBoolean.get());
                System.out.println(Thread.currentThread().getName() + " is setting atomic to true");
                atomicBoolean.set(true);
                System.out.println(Thread.currentThread().getName() + " " + atomicBoolean.get());
            }           
        }.start();                
    }
}
Run Code Online (Sandbox Code Playgroud)

输出

T1 is waiting for T3 set Atomic to true. Current is false
T1 is waiting for T3 set Atomic to true. Current is false
T3 is setting atomic to true
T2 false
T3 true (*)
T1 is waiting for T3 set Atomic to true. Current is false (*)
T2 true
Done. Atomic now is false
T2 false
Run Code Online (Sandbox Code Playgroud)

在第 2 行 (*),虽然 T3 设置AtomicBoolean为 true,但之后 T1 读取的值为 false。那么,T1和T3AtomicBoolean是同时接入的吗?我无法理解如何AtomicBoolean工作。

有谁能够帮助我?

Mad*_*apu 5

AtomicBoolean 绝对是原子和线程安全的。

但是在您的示例中,您试图根据System.out.println打印具有误导性的日志的顺序来测试 AtomicBoolean 的这种原子性质。

所以如果我们看一下System.out.println()代码:

public void println(String x) {
    synchronized (this) {
        print(x);
        newLine();
    }
}
Run Code Online (Sandbox Code Playgroud)

我们将println()在上下文中看到使用上述方法的事件流。

简答

线程 T1 打印 -> 正在等待 T3 将 Atomic 设置为 true。当前为 false
线程 T1 打印 -> 正在等待 T3 将 Atomic 设置为 true。当前为假
线程 T3 打印 -> T3 正在将原子设置为真
线程 T1调用 sysout进行打印 -> 正在等待 T3 将原子设置为真。当前为假(刚刚调用了sysout 方法但尚未获得锁
线程 T3 打印 -> T3 打印真
线程 T1 sysout 完成并打印 -> 正在等待 T3 将原子设置为真。当前是假的

日志的顺序给人的印象是 T1 没有读取 atomicBoolean 的当前值,而这是因为在执行System.out.println.

详细序列

应用程序以falsefor 的初始值开始atomicBoolean

final AtomicBoolean atomicBoolean = new AtomicBoolean(false);
Run Code Online (Sandbox Code Playgroud)

输出中最初的两个日志来自 T1,正如预期的那样,它打印出atomicBooleanas的值false。现在我们将忽略 T2 以简化,因为即使有两个线程我们也可以看到流程。

现在 T3 开始执行,并且atomicBooleantrue按照输出中的指示执行。

T3 is setting atomic to true
Run Code Online (Sandbox Code Playgroud)

并且在打印上述行之后,T1 立即有机会执行。在这一点上的价值atomicBooleanfalse。因此 JVM 创建字符串T1 is waiting for T3 set Atomic to true. Current is false和关于调用或刚刚进入System.out.println方法但尚未到达synchronized(this)语句,因此尚未在 上获得锁this

在这一点上可能发生的T3已经得到了它的转向继续执行,使得atomicBooleantrue还打印线T3 true使用System.out.println(),即,获取和释放锁(上this)。

现在 T1 从它上次离开的地方恢复执行,即 System.out.println。但请记住,它试图打印的 String 的值已经建立,它的值为T1 is waiting for T3 set Atomic to true. Current is false. 所以现在 T1 打印这一行并继续。

有效地使用此流程,日志将如您所见。

T3 true
T1 is waiting for T3 set Atomic to true. Current is false
Run Code Online (Sandbox Code Playgroud)

图示

下面是 T1 和 T3 的流程,并且(尝试)捕获了上述讨论。----表示线程当前正在执行。空格表示它正在等待轮到它。

    1(false) 1(false)           1(false)just invoked   1(false)completed
T1 -------------------          ------                ------------------
T3                    ----------      ----------------  
                       2(false)        3(true)

LEGEND:
 1(false) - printing of T1 is waiting for T3 set Atomic to true. Current is false
 2(false) - printing of T3 is setting atomic to true
 3(true) - printing of T3 true
Run Code Online (Sandbox Code Playgroud)