Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/329.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 原子布尔值保证吗;安全螺纹;?_Java_Multithreading_Atomic - Fatal编程技术网

Java 原子布尔值保证吗;安全螺纹;?

Java 原子布尔值保证吗;安全螺纹;?,java,multithreading,atomic,Java,Multithreading,Atomic,根据我在互联网上读到的一些文件,原子类变量如AtomicInteger,AtomicLong,。。。只允许1个线程同时访问它们。但是当我尝试使用原子布尔进行测试时,出现了一些问题。比如说 public class TestAtomicBoolean { public static void main(String[] args) { final AtomicBoolean atomicBoolean = new AtomicBoolean(false);

根据我在互联网上读到的一些文件,原子类变量如
AtomicInteger
AtomicLong
,。。。只允许1个线程同时访问它们。但是当我尝试使用原子布尔进行测试时,出现了一些问题。比如说

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
?我不明白原子布尔是如何工作的

有人能帮我吗?

与其说是指“一些文件”,不如试着在


考虑原子包中的类的一个简单快捷的方法是,每个方法(如get、set、compareAndSet)的行为都像是同步的(忘记了惰性和弱方法)。

原子布尔
绝对是原子的和线程安全的

但在您的示例中,您试图测试原子布尔的原子性质,依赖于
System.out.println
打印日志的顺序,这是误导性的

因此,如果我们看一下
System.out.println()
code:

public void println(String x) {
    synchronized (this) {
        print(x);
        newLine();
    }
}
我们将在上下文中看到使用上述
println()
方法的事件流

简短回答

线程T1打印->正在等待T3将原子设置为true。电流为假
线程T1打印->正在等待T3将原子设置为true。电流为假
线程T3打印->T3正在将原子设置为true
线程T1调用sysout打印->正在等待T3将原子设置为true。Current为false(仅称为sysout方法,但尚未获取锁)
线程T3打印->打印T3真值
线程T1sysout complete和prints->正在等待T3设置为true。电流是假的

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

详细顺序

对于
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正在等待T3将Atomic设置为true。Current为false
且与调用有关,或刚进入
System.out.println
方法,但尚未到达
synchronized(this)
语句,因此未获得对
this
的锁定

在这一点上,可能会发生T3已轮到继续执行,并使
原子布尔值
变为
,并且还使用
System.out.println()
打印行
T3真
,即获取并释放锁(在
上此

现在T1从上次离开的位置恢复执行,即,
System.out.println
。但请记住,它试图打印的字符串的值已经生成,其值为
T1正在等待T3设置为true。当前值为false
。现在T1打印这条线并继续

通过此流程,日志将与您观察到的一样有效

T3 true
T1 is waiting for T3 set Atomic to true. Current is false
图形表示法

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

@ElliottFrisch你能解释得更清楚些吗(没有保证线程安全的灵丹妙药。即使您的代码执行的每个操作都是单独的线程安全的,也不一定会使整个操作都是线程安全的。我已经阅读了这篇官方文档,但我仍然不明白:(“AtomicBoolean:一个可以自动更新的布尔值。”在我的例子中,它不是“原子的”:s 2个线程可以同时访问它:使用日志框架log4j进行多线程@mube坦率地说,不确定这样的日志记录是否已经存在或可以在我们的代码中实现。我可以考虑的一个选项是编写一个实用程序类,并使用内部调用
sysout()的
static synchronized
方法
。但我确实感觉到,而且几乎可以看到,仍然有一个小窗口可以出现上述流量。我知道了。非常感谢!