java - 这种行为背后的原因是什么(线程)
问题描述
我正在研究线程,并决定在我的重点代码行运行之前和之后添加一些额外的文本,以供参考。我希望在开头和结尾处获得一个“额外文本”。然而......这并没有发生,当我运行它时,第二个“额外文本”刚刚出现在第四个位置。我是初学者,需要知道为什么会这样……
- -代码 - -
class Hi extends Thread{
public void run(){
for(int i=1; i<=5; i++){
System.out.println("HI!");
try{
Thread.sleep(500);
} catch(InterruptedException e){}
}
}
}
class Hey extends Thread{
public void run(){
for(int i=1; i<=5; i++){
System.out.println("HEY!");
try{
Thread.sleep(500);
} catch(InterruptedException e){}
}
}
}
public class MyClass {
public static void main(String[] args){
Hi hiObj = new Hi();
Hey heyObj = new Hey();
System.out.println("extra-text");
hiObj.start();
heyObj.start();
try {
Thread.currentThread().sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("extra-text");
}
}
- -输出 - -
extra-text
HI!
HEY!
extra-text
HEY!
HI!
HEY!
HI!
HEY!
HI!
HEY!
HI!
解决方案
这是一个常见的并发错误。
程序的 main 方法在主线程上运行。因此,在您启动hiObj
andheyObj
线程之前,您已经拥有了一个线程。启动两个新线程后,您将拥有三个。每个都同时执行。这意味着每个线程都可以执行代码而无需等待其他线程。线程之间不保证顺序。
这会导致您观察到的行为。在启动hiObj
或heyObj
启动之前,在主线程上运行的 main 方法会打印"extra-text"
. 接下来,启动 hiObj 和 heyObj。主线程到达Thread.currentThead().sleep(10)
导致它暂停执行 10 毫秒的行。在大多数机器(包括您的机器)上,这足以让其他两个线程开始执行。每个线程for
在其方法中开始循环run
并打印"HI"
或"HEY"
。因此,输出的前三行是(不保证"HI"
和的顺序):"HEY"
"extra-text"
"HI"
"HEY"
接下来,hiObj
andheyObj
线程到达Thread.sleep(500)
导致它们暂停执行 500 毫秒的行。10 毫秒过去后,主线程将完成睡眠并恢复。请注意,此时hiObj
或heyObj
线程都无法恢复。因此,打印的下一行将是在 中执行的下一行main
。这是"extra-text"
. 因此,预期的输出是:
"extra-text"
"HI"
"HEY"
"extra-text"
在接下来的几秒钟内,将出现来自hiObj
和heyObj
线程的剩余打印。在 Java 中,只有在所有其他线程都退出后,主线程才会退出(除非System.exit
被调用或存在未捕获的异常)。main
在这种情况下,这意味着程序只有在执行结束并且hiObj
' 和heyObj
' 的 run 方法都返回时才会退出。
要更改程序以使最后一个"extra-text"
始终打印在最后,您必须使主线程等待hiObj
和heyObj
线程完成。在 Java 中,有一个方法 on Thead
calledjoin
会导致调用线程等待,直到加入的线程死亡。在您的程序中,您可以修改MyClass
为如下所示:
public class MyClass {
public static void main(String[] args){
Hi hiObj = new Hi();
Hey heyObj = new Hey();
System.out.println("extra-text");
hiObj.start();
heyObj.start();
try {
Thread.currentThread().sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
hiObj.join();
heyObj.join();
System.out.println("extra-text");
}
}
通过此更改,main
将首先等待hiObj
完成,然后等待完成,然后再heyObj
打印"extra-text"
。
推荐阅读
- powershell - For-each 循环无法处理所有字符串
- c# - 硬币计数显示显示不同数量 - Unity 2D游戏
- google-sheets - 需要一个复数乘以一个值的公式(不是每年)
- assembly - 如何检查输入是否为int?
- agens-graph - 如何在 AgensGraph 上更快地获取标签的最大位置 ID?
- python - Python Timer 是否可以通过检查它是否存在来取消?
- reactjs - 我们如何使用 TSX 为反应元素指定类型
- c++ - 我可以有一个不同于 linux 环境中的本地 C++ 编译器吗?
- java - 正则表达式检索任何字母数字 otp 代码
- git - 如何检测 git (github) 中的提交更改