假设我们有以下C ++程序
void hello (){
std :: cout << "HELLO"<<std::endl ;
}
int main(){
std:: thread t(hello) ;
t.join() ;
}
如果我们不在此代码中调用join,则我们的程序将崩溃,因为主线程将在线程t1完成之前终止。 但是,如果我们在Java中具有相同的程序,则即使main不等待线程,该程序也可以正常执行。
public class HelloWorld {
public static void main(String[] args) {
Thread t = new Thread(new Hello());
t.start();
}
}
class Hello implements Runnable {
public void run() {
System.out.println("Hello") ;
}
}
那么为什么在Java中程序不会崩溃?即使主程序先完成线程也如何执行?
答案 0 :(得分:5)
以下是直接的答案:您的应用程序崩溃是因为如果线程未加入且未分离,则std::thread
会在其析构函数中调用std::terminate
。静默忘记未分离的线程,这被认为是一个讨厌的错误。
如果在从main返回之前分离线程,则可以避免立即崩溃。但是,由于访问std::cout
(这是一个全局对象),您仍然可能会发生各种可能的烟花事件,并且从main
返回后,该对象将被销毁(可能在线程仍在访问时)它。
答案 1 :(得分:4)
这很简单:与C ++(main
完成后终止)相反,Java程序仅在所有(非守护程序)线程(包括main)都已经完成(例如,{ {3}} Oracle线程文档):
相反,Java虚拟机启动时,通常只有一个 非守护程序线程(通常调用一些名为main的方法 指定课程)。 Java虚拟机继续执行 线程,直到发生以下任何一种情况:
a。已调用类Runtime的exit方法,并且其安全性 经理已允许进行退出操作。
b。不是守护程序线程的所有线程都已死亡,原因可能是 从调用返回到run方法或通过引发异常 传播到run方法之外。
C ++将开始以静态存储持续时间破坏对象,并且如果分离线程仍在运行并访问此类对象,则会产生未定义的行为(例如,this C ++标准草案涉及程序终止):
3.6.3终止
已初始化对象(即对象)的析构函数([class.dtor]) 其生存期([basic.life])已开始)和静态存储期限 被称为从主返回,并由于 调用std :: exit([support.start.term])。
答案 2 :(得分:3)
这是因为JVM具有与C / C ++不同的终止进程的规则。在JVM上,一旦不再有非守护进程线程在运行,进程就会终止。 C或C ++应用程序的main
函数返回后将终止。参见If you return from the main thread, does the process exit?:
当您退出主线程时,无论是否还有任何工作线程处于活动状态,C运行时库都会自动调用ExitProcess。控制台程序的这种行为是C语言所强制执行的,它表示(5.1.2.2.3)“从初始调用返回到主函数等同于以主函数返回的值作为调用退出函数。论点。” C ++语言具有等效要求(3.6.1)。大概是C运行时人员将此行为带给WinMain以获得一致性。
C行为就像您在Java System.exit
末尾调用main
一样。