Search code examples
javamultithreadingjava-threads

If join blocks the main thread, why it doesn't block in loop?


The join() method of a Thread instance can be used to "join" the start of a thread's execution to the end of another thread's execution so that a thread will not start running until another thread has ended. If join() is called on a Thread instance, the currently running thread will block until the Thread instance has finished executing

But if i a have multiple threads and when I call join inside the loop. All threads run in parallel. But according to join concept first joined thread should finish then only main thread should allow to join the other threads.

public class MultiThreading implements Runnable {


private int name;
public MultiThreading(int number) {
    name =number;
}

@Override
public void run() {
    for (int i = 0; i <= 10; i++ ) {

           System.out.println("Thread number :" + name +" Printed value "+i);

        try {
            Thread.sleep(100);
        } catch (final InterruptedException e) {
            return;
        }
    }
}


public static void main(String[] args) throws InterruptedException {

    final Thread[] workers = new Thread[3];
    for (int i = 0; i < nthreads; ++i) {
        workers[i] = new Thread(new MultiThreading(i));
    }
    for (final Thread t : workers) {
        t.start();

    }

    for (final Thread t : workers) {
        t.join();
        System.out.println("Thread joind to main thread : " + t.getName());
    }
    System.out.println("Main thread ends");
}

}

In the above code, if the first thread is joined then the main thread should be blocked and it shouldn't let other thread to join (until the joined thread finished the execution of run method). But all the threads are joined in parallel. The output is like -

Thread number :0 Printed value 0
Thread number :1 Printed value 0
Thread number :2 Printed value 0
Thread number :0 Printed value 1
Thread number :1 Printed value 1
Thread number :2 Printed value 1
Thread number :0 Printed value 2
Thread number :1 Printed value 2
Thread number :2 Printed value 2
Thread number :0 Printed value 3
Thread number :1 Printed value 3
Thread number :2 Printed value 3
Thread number :0 Printed value 4
Thread number :1 Printed value 4
Thread number :2 Printed value 4
Thread number :1 Printed value 5
Thread number :0 Printed value 5
Thread number :2 Printed value 5
Thread number :0 Printed value 6
Thread number :1 Printed value 6
Thread number :2 Printed value 6
Thread number :1 Printed value 7
Thread number :0 Printed value 7
Thread number :2 Printed value 7
Thread number :0 Printed value 8
Thread number :1 Printed value 8
Thread number :2 Printed value 8
Thread number :1 Printed value 9
Thread number :0 Printed value 9
Thread number :2 Printed value 9
Thread number :1 Printed value 10
Thread number :0 Printed value 10
Thread number :2 Printed value 10
Thread joind to main thread : Thread-0
Thread joind to main thread : Thread-1
Thread joind to main thread : Thread-2
Main thread ends

Solution

  • First of all:

    The join() method of a Thread instance can be used to "join" the start of a thread's execution to the end of another thread's execution

    That is a misconception: this has nothing to do with starting Threads. Join only does this: a running thread will wait until the other thread has ended.

    When you do someThread.join(), then the thread invoking that method will wait until someThread has ended!

    But all the threads are joined in parallel.

    Yes, because they are all done.

    Your threads do all the exact same thing, so besides a few nanoseconds here or there (which are mostly invalidated due to the fact that writing to System.out effectively synchronizes stuff anyway) they all need the same amount of time.

    So by the time you join the first thread ... the other two threads will be done. So the first call to join() makes the "main" thread wait for the first thread to end, and the subsequent calls happen "instantly", because these threads are done, too.

    In order to delay things, make the number of loops a parameter of your MultiThreading class, and then ensure that your threads will require for different amounts of time. If Thread-0 does 10 loops, and Thread-1 goes 20, and the Thread-2 will do 30, you will see that each join does in fact wait for the corresponding thread to end.

    Long story short: you start all your threads immediately, thus they instantly start running in parallel. The later join call simply delays the main thread from progressing, until each of the worker threads has ended.