繁体   English   中英

意外的线程行为。 能见度

[英]Unexpected thread behavior. Visibility

我有以下代码:

public static boolean turn = true;

public static void main(String[] args) {
    Runnable r1 = new Runnable() {
        public void run() {
            while (true) {
                while (turn) {
                    System.out.print("a");
                    turn = false;
                }
            }
        }
    };
    Runnable r2 = new Runnable() {
        public void run() {
            while (true) {
                while (!turn) {
                    System.out.print("b");
                    turn = true;
                }
            }
        }
    };
    Thread t1 = new Thread(r1);
    Thread t2 = new Thread(r2);
    t1.start();
    t2.start();
}

在课堂上,我们了解了使用非同步代码时可能发生的“可见性”问题。 我知道,为了节省时间,编译器将为循环决定对CPU缓存的抓取turn ,这意味着线程不会知道RAM中的turn值是否已更改,因为他不检查它。

据我了解,我希望代码像这样运行:

T1将看到转为true->进入循环并打印->将转为false->被卡住

T2会认为转弯没有改变->会被卡住

我希望如果T1在T2之前开始:只会打印'a',并且两个线程都将在无限循环中运行而无需打印其他任何内容

但是,当我运行代码时,有时我会在两个线程卡住之前得到一些“ abab ....”。

我想念什么?

编辑:

以下代码完成了我所期望的:线程将在无限循环中运行:

public class Test extends Thread {
boolean keepRunning = true;

public void run() {
    long count = 0;
    while (keepRunning) {
        count++;
    }
    System.out.println("Thread terminated." + count);
}

public static void main(String[] args) throws InterruptedException {
    Test t = new Test();
    t.start();
    Thread.sleep(1000);
    t.keepRunning = false;
    System.out.println("keepRunning set to false.");
}

}

它们彼此之间有何不同?

当我运行代码时,有时我会在两个线程卡住之前得到一些“ abab ....”。

我怀疑正在发生的事情是,在对代码进行JIT编译时,行为正在改变。 在JIT编译之前,写操作是可见的,因为解释器正在执行写操作。 在JIT编译之后,缓存刷新或读取已被优化……因为内存模型允许这样做。

我想念什么?

您缺少的是您期望未指定的行为是一致的。 不一定是。 毕竟,它是未指定的! (这是正确的,即使我上面提出的解释不正确。)

turn不是不稳定的事实并不意味着您的代码会中断,而可能会中断。 就我们所知,线程在任何给定时刻都可能看到false或true。 无需特别说明,就可以随意清除缓存,线程可以保留其缓存等。

这可能是因为您的代码正在遭受System.out.print副作用,该副作用在内部写入同步方法:

  521       private void write(String s) {
  522           try {
  523               synchronized (this) {

资料来源-DocJar

同步的内存影响可能会刷新缓存,因此会影响您的代码。

正如@Stephen C所说,它也可能是JIT,它可能会进行布尔检查,因为它假定值不会由于另一个线程而改变。

因此,在到目前为止提到的三种不同的可能性中,它们都可能是影响代码行为的因素。 可见性是一个因素,而不是决定因素。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM