Search code examples
javac++multithreadingrunnable

Why a multithreading C++ program crashes if we don't use join(), while a similar Java program doesn't


Let's say we have the following C++ program

void hello (){
   std :: cout << "HELLO"<<std::endl ;
}

int main(){

    std:: thread t(hello) ;
    t.join() ;

}

If we don't call join in this code, our program will crash because the main thread will terminate before the thread t1 is done. But if we have the same program in Java, the program executes normally even if the main doesn't wait for the thread.

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") ;

}
}

So why in Java the program doesn't crash? how the thread is executed even if the main finishes first ?


Solution

  • It's rather simple: In contrast to C++, which terminates once main has finished, a java program ends only if all (non-deamon) threads (including main) have finished (cf., for example, this oracle thread documentation):

    When a Java Virtual Machine starts up, there is usually a single non-daemon thread (which typically calls the method named main of some designated class). The Java Virtual Machine continues to execute threads until either of the following occurs:

    a. The exit method of class Runtime has been called and the security manager has permitted the exit operation to take place.

    b. All threads that are not daemon threads have died, either by returning from the call to the run method or by throwing an exception that propagates beyond the run method.

    C++, in contrast, will start destructing objects with static storage duration, and if a detached thread is still running and accessing such objects, this yields undefined behaviour (cf., for example, this C++ standard draft concerning program termination):

    3.6.3 Termination

    Destructors ([class.dtor]) for initialized objects (that is, objects whose lifetime ([basic.life]) has begun) with static storage duration are called as a result of returning from main and as a result of calling std::exit ([support.start.term]).