Home > database >  If java normal threads don't call "join", does it lead to unknown behavior before fin
If java normal threads don't call "join", does it lead to unknown behavior before fin

Time:06-20

Normal java threads, not daemon threads, seem to execute till end, then main thread finishes, like this:

    public static void main(String[] args) {
        for(int i = 0; i < 3;   i){
            new Thread(new Runnable(){
                @Override
                public void run() {
                    try {
                        Thread.sleep(2000);
                        System.out.println("Does this still print?");
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }).start();
        }
        // Java normal threads don't have to call join, they'll still wait to finish.
        System.out.println("Main thread start");
    }

It will print:

Main thread start
i = 2
i = 0
i = 1
Does this still print?
Does this still print?
Does this still print?

What I saw here is, Java normal threads don't have to call join() and their holder still wait for them to finish. Not sure if my program is too simple to encounter any undefined behavior, could you kindly give some hints when should we use join()?

Thanks.

CodePudding user response:

t.join() does not do anything to thread t in Java. All it does is not return until thread t has finished.

A Java program's main() thread does not wait for any other thread to finish after main() returns. It just ends, and any other non-daemon threads keep running.

CodePudding user response:

Java is not like Go. In Go the program continues only as long as the main thread is alive, in Java any living nondaemon thread keeps the jvm around. In your code the main thread kicks off other threads and then dies. The new threads run to completion even though the main thread is long gone.

For "undefined behavior" I'm guessing you mean data races, or memory visibility issues, where you can't rely on one thing happening before another (for races) or on a value being visible across threads (for vidibility). Calling join does create a happens-before edge. So does calling println (since it acquires a lock). The Java language spec has a list of things that create a happens-before edge.

Calling get on a Future blocks until the future is done similar to how calling join on a Thread blocks until the thread is finished. If you use higher level constructs than just threads, whether it's executor services, CompletableFuture, reactive libraries, actor systems, or other concurrency models, then those are to different extents shielding you from the Thread api and you don't need join so much.

  • Related