Java 线程意外操纵的变量 公共类主{ 静态int i=0; 公共静态void main(字符串[]args){ 对于(;iSystem.out.println(i)).start(); } }
我希望上面的代码也能打印出来 0Java 线程意外操纵的变量 公共类主{ 静态int i=0; 公共静态void main(字符串[]args){ 对于(;iSystem.out.println(i)).start(); } },java,multithreading,concurrency,Java,Multithreading,Concurrency,我希望上面的代码也能打印出来 0 一, 或 1 0 但令我惊讶的是,我得到了 2 二, 我运行同样的程序,它也给我同样的结果。但是如果你像那样运行它 public class Main { static int i = 0; public static void main(String[] args) { for (; i < 2; i++) new Thread(() -> System.out.println(i)).st
一, 或 1
0 但令我惊讶的是,我得到了 2
二,
我运行同样的程序,它也给我同样的结果。但是如果你像那样运行它
public class Main {
static int i = 0;
public static void main(String[] args) {
for (; i < 2; i++)
new Thread(() -> System.out.println(i)).start();
}
}
(;i<2;i++)的{
睡眠(10);
新线程(()->System.out.println(i)).start();
}
结果变成
1二, 如果在
新线程(()->System.out.println(i)).start()下面添加Thread.sleep(10)
代码>它输出
0
一,
这是因为当前线程(main)在线程之前执行循环
主线程启动
循环开始
线程-1已创建。(线程仍处于空闲状态)
循环连续。(i=1)
线程-2已创建。(线程处于空闲状态)
循环结束
主线程结束
线程1和线程2在代码的第2步和第7步之间开始。操作系统处理线程调度,因此您无法在该程序中预期结果。我运行相同的程序,它也为我提供相同的结果。但是如果你像那样运行它
public class Main {
static int i = 0;
public static void main(String[] args) {
for (; i < 2; i++)
new Thread(() -> System.out.println(i)).start();
}
}
(;i<2;i++)的{
睡眠(10);
新线程(()->System.out.println(i)).start();
}
结果变成
1
二,
如果在新线程(()->System.out.println(i)).start()下面添加Thread.sleep(10)
代码>它输出
0
一,
这是因为当前线程(main)在线程之前执行循环
主线程启动
循环开始
线程-1已创建。(线程仍处于空闲状态)
循环连续。(i=1)
线程-2已创建。(线程处于空闲状态)
循环结束
主线程结束
线程1和线程2在代码的第2步和第7步之间开始。操作系统处理线程调度,因此您无法在此程序中预期结果。结果因调度程序而异。无法预测它总是2,2
。见下图。最终可能会得到不同的值。这是因为操作系统有自己处理线程的方式。您可以阅读更多关于线程的信息-----------------------------------------------------------------------------------------------图像显示eclipse输出。结果因调度程序而异。无法预测它总是2,2
。见下图。最终可能会得到不同的值。这是因为操作系统有自己处理线程的方式。您可以阅读更多关于线程的信息--------------------------------------------------------------------------------------------这些图像显示eclipse输出。当您在类Main
的主体中引用i
时,您真正要做的是引用静态变量Main.i
(编译器很有礼貌,不会让您键入完整路径)Main.i
可以从静态上下文进行计算。因此,如果lambda被去除到该方法中
for (; i < 2; i++) {
Thread.sleep(10);
new Thread(() -> System.out.println(i)).start();
}
现在应该更清楚的是,有多个线程竞相访问共享(可变!)变量Main.i
;主线程正在更新它,而创建的线程正在读取它。因为新线程中的读取是快速的,所以您无法保证打印出什么。当您在类Main
的主体中引用i
时,您真正做的是引用静态变量Main.i
(编译器很礼貌,不会让您键入完整路径。)本例中的lambda没有捕获任何东西Main.i
可以从静态上下文进行计算。因此,如果lambda被去除到该方法中
for (; i < 2; i++) {
Thread.sleep(10);
new Thread(() -> System.out.println(i)).start();
}
现在应该更清楚的是,有多个线程竞相访问共享(可变!)变量Main.i
;主线程正在更新它,而创建的线程正在读取它。由于新线程中的读取是快速的,因此无法保证打印出来的内容。有一个dupe(不是完美的,但是)解释了当访问lambda时(这里由线程本身)将对lambda进行评估,i
在线程实际启动之前已经是“2”(在某些情况下也可以是“1”)。这一切都取决于调度程序。有一个dupe(不是完美的,但是)解释了当访问lambda时(这里由线程本身)将对lambda进行评估,i
在线程实际启动之前已经是“2”(在某些情况下也可以是“1”)。这完全取决于调度程序。啊,我错过了第二部分,你移动了线程。sleep
。没关系:)。啊,我错过了你移动线程的第二部分。sleep
。没关系:)。嗨,布莱恩,非常感谢你向我解释了这么简单的事情。我需要再看一次你的书。嗨,布莱恩,非常感谢你向我解释了这么一点基本的事情。我需要把你的书再读一遍。