变量意外地被线程操纵

时间:2016-06-27 00:28:29

标签: java multithreading concurrency

public class Main {
    static int i = 0;

    public static void main(String[] args) {
        for (; i < 2; i++)
            new Thread(() -> System.out.println(i)).start();
    }
}

我希望上面的代码打印出来

  

0
  1

  

1
  0

但令我惊讶的是我得到了

  

2
  2

3 个答案:

答案 0 :(得分:4)

当你在类i的主体中引用Main时,你真正在做的是引用静态变量Main.i(编译器是礼貌的,不会让你输入完整路径。)在这种情况下,lambda没有捕获任何东西;可以从静态上下文中评估Main.i。因此,如果lambda被解除了方法

public static void lambda$23() {
    System.out.println(Main.i);
}

现在应该更清楚的是,你有多个线程竞相访问共享(mutable!)变量Main.i;主线程正在更新它,并且创建的线程正在读取它。而且由于新线程中的读取很复杂,因此无法保证打印出来的内容。

答案 1 :(得分:2)

我运行相同的程序,它也为我提供了相同的结果。但如果你像那样运行它

for (; i < 2; i++) {
    Thread.sleep(10);
    new Thread(() -> System.out.println(i)).start();
}

结果成了

  

1
  2

如果您在Thread.sleep(10)输出

下面添加new Thread(() -> System.out.println(i)).start();
  

0
  1

因为当前线程(main)在线程之前执行循环。

  1. 主线程开始。
  2. 循环开始。
  3. 线程 - 1已创建。(线程仍处于空闲状态)
  4. 循环连续。(i = 1)
  5. 线程 - 2创建。(线程空闲)
  6. 循环结束。
  7. 主线程结束。
  8. 线程1和线程2在代码的第2步和第7步之间开始。操作系统处理线程调度,因此您无法在此程序中获得结果。

答案 2 :(得分:1)

结果因调度程序而异。无法预测它总是2,2。见下图。您最终也可能获得不同的值。这是因为OS有自己的处理线程的方式。您可以阅读有关线程here enter image description here的更多信息--------------------------------- -------------------------------------------------- ------------------------------------------------- { {3}}图像显示了日食输出。