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

时间:2016-03-24 04:14:28

标签: java multithreading atomic

根据我在互联网上阅读的一些文档,像AtomicIntegerAtomicLong这样的类Atomic的变量只允许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();                
    }
}

输出

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

在2行(*),虽然T3将AtomicBoolean设置为true,但在此之后,T1读取的值为false。那么,T1和T3同时访问AtomicBoolean?我无法理解AtomicBoolean的工作原理。

有人能帮助我吗?

2 个答案:

答案 0 :(得分:3)

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

但是在你的例子中,你试图依靠命令来测试AtomicBoolean的这种原子性质,System.out.println打印出误导性的日志。

因此,如果我们查看System.out.println()代码:

public void println(String x) {
    synchronized (this) {
        print(x);
        newLine();
    }
}

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

简答

线程T1打印 - >等待T3设置Atomic为true。当前是假的 线程T1打印 - >等待T3设置Atomic为true。当前是假的 线程T3打印 - > T3将原子设置为真实 线程T1 调用sysout 进行打印 - >等待T3设置Atomic为true。当前是错误的(仅称为 sysout方法,但锁定尚未获得
线程T3打印 - >打印T3真实 线程T1 sysout完成并打印 - >等待T3设置Atomic为true。当前是假的

日志的顺序给人的印象是T1没有读取atomicBoolean的当前值,而这是因为在执行System.out.println时可能发生的线程交错。

详细序列

应用程序以false

的初始值atomicBoolean开头
final AtomicBoolean atomicBoolean = new AtomicBoolean(false);

输出中的初始两个日志来自T1,并且atomicBoolean的值为false。现在我们将忽略T2以简化,因为即使有两个线程我们也可以看到流程。

现在T3开始执行,并且即将atomicBoolean转为true,如输出中所示。

T3 is setting atomic to true

在打印完上面一行后,T1就有机会执行。此时atomicBoolean的值为false。因此,JVM创建字符串T1 is waiting for T3 set Atomic to true. Current is false以及有关调用或刚刚输入System.out.println方法但尚未到达synchronized(this)语句,因此在this上尚未获得锁定。< / p>

此时可能会发生T3轮流继续执行并将atomicBoolean转换为true并使用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

图示

下面是流程w.r.t T1&amp; 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

答案 1 :(得分:0)

您可能希望尝试阅读https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/atomic/package-summary.html

上的官方文档,而不是参考某些文档&#34;

考虑原子包中的类的一种快速简便的方法是,每个方法(如get,set,compareAndSet)都表现得好像是同步的(忘记了懒惰和弱方法)。