Abhiroop Nandi Ray
Abhiroop Nandi Ray

Reputation: 397

Is the join() method in Thread guaranteed to work perfectly or it is also dependent on individual JVM?

Overview

I was learning and working with Threads in java. I just began investigating the join() method. I understand that it lets the current thread and forces it to wait until the thread.join() call ends/dead/terminates.

Here is the code I tried to utilize to explore the functionality:

ThreadJoinMain

package com.threeadjoin.main;

import sun.nio.ch.ThreadPool;

public class ThreadJoinMain {

public static void main(String[] args) {
    CustomThreadOne threadOne = new CustomThreadOne();

        Thread t1 = new Thread(threadOne);
        t1.setName("Thread 1");
        t1.setPriority(10);

        Thread t2 = new Thread(threadOne);
        t2.setName("Thread 2");

        /*Thread t3 = new Thread(threadOne);
        t3.setName("Thread 3");*/

        try{
            t1.join();
            //t2.join();
        }
        catch (InterruptedException e){
            e.printStackTrace();
        }

        t1.start();
        t2.start();
        //t3.start();

    }
}

CustomThreadOne

package com.threeadjoin.main;

public class CustomThreadOne implements Runnable{
    @Override
    public void run() {
        for(int i = 0; i < 10; i ++){
            System.out.println("Inside thread: " + 
Thread.currentThread().getName() + " value: " + i);
        }
    }
}

Most of the time it is giving satisfactory result like this:

Inside thread: Thread 1 value: 0
Inside thread: Thread 1 value: 1
Inside thread: Thread 1 value: 2
Inside thread: Thread 1 value: 3
Inside thread: Thread 1 value: 4
Inside thread: Thread 1 value: 5
Inside thread: Thread 1 value: 6
Inside thread: Thread 1 value: 7
Inside thread: Thread 1 value: 8
Inside thread: Thread 1 value: 9
Inside thread: Thread 2 value: 0
Inside thread: Thread 2 value: 1
Inside thread: Thread 2 value: 2
Inside thread: Thread 2 value: 3
Inside thread: Thread 2 value: 4
Inside thread: Thread 2 value: 5
Inside thread: Thread 2 value: 6
Inside thread: Thread 2 value: 7
Inside thread: Thread 2 value: 8

But, if I run this code continuously without making any changes or forcefully re-building it, sometimes (very few though) the output is coming like this:

Inside thread: Thread 1 value: 0
Inside thread: Thread 2 value: 0
Inside thread: Thread 1 value: 1
Inside thread: Thread 2 value: 1
Inside thread: Thread 1 value: 2
Inside thread: Thread 2 value: 2
Inside thread: Thread 1 value: 3
Inside thread: Thread 2 value: 3
Inside thread: Thread 1 value: 4
Inside thread: Thread 2 value: 4
Inside thread: Thread 1 value: 5
Inside thread: Thread 2 value: 5
Inside thread: Thread 1 value: 6
Inside thread: Thread 1 value: 7
Inside thread: Thread 1 value: 8
Inside thread: Thread 2 value: 6
Inside thread: Thread 1 value: 9
Inside thread: Thread 2 value: 7
Inside thread: Thread 2 value: 8
Inside thread: Thread 2 value: 9

OR this:

Inside thread: Thread 2 value: 0
Inside thread: Thread 1 value: 0
Inside thread: Thread 2 value: 1
Inside thread: Thread 1 value: 1
Inside thread: Thread 2 value: 2
Inside thread: Thread 1 value: 2
Inside thread: Thread 2 value: 3
Inside thread: Thread 1 value: 3
Inside thread: Thread 2 value: 4
Inside thread: Thread 1 value: 4
Inside thread: Thread 2 value: 5
Inside thread: Thread 1 value: 5
Inside thread: Thread 2 value: 6
Inside thread: Thread 1 value: 6
Inside thread: Thread 2 value: 7
Inside thread: Thread 1 value: 7
Inside thread: Thread 2 value: 8
Inside thread: Thread 1 value: 8
Inside thread: Thread 2 value: 9
Inside thread: Thread 1 value: 9

Is there anything I am missing here?

Upvotes: 0

Views: 51

Answers (1)

Impurity
Impurity

Reputation: 1132

Overview

Great question! Yes! It is guaranteed to work as intended, and does not depend on the JVM. However, I see quite a few points of confusion in your source code so I will step through the semantics on join() with a similar application. Lets investigate the example below.

Example Application

public static void main(String[] args) {
    // Create threads t1 -> t3
    Thread t1 = new Thread(threadOne);
    t1.setName("Thread 1");
    Thread t2 = new Thread(threadOne);
    t2.setName("Thread 2");
    Thread t3 = new Thread(threadOne);
    t3.setName("Thread 3");

    //////////// Explanation 1 /////////////

    t1.start(); // Begin execution of t1
    t2.start(); // Begin execution of t2

    //////////// Explanation 2 /////////////

     try {
         t1.join(); // Force main thread to wait for t1
    //////////// Explanation 3 /////////////
         t2.join(); // Force main thread to wait for t2
    //////////// Explanation 4 /////////////

         t3.start(); // Begin execution of t3
         t3.join(); // Force main thread to wait for t3
    //////////// Explanation 5 /////////////
     } catch (InterruptedException e) {
            e.printStackTrace();
     }
}

Here, there are actually 4 threads present in this code: main, t1, t2, t3. The main thread is the starting thread that the application creates and utilizes to run the application.

Explanation 1

At this point, only 1 thread is executing: the main thread. Although t1->t3 have been created, they have not begun execution.

Explanation 2

Here, we have started t1 and t2 so that there are 3 executing threads: t1, t2, and main.

Explanation 3

At the t1.join(), the main thread (or the calling thread) waits for the execution of t1 to finish. Once it has finished, the main thread continues executing. At this point, t2 was executing in parallel to the main and t1.

Explanation 4

The main thread again waits for execution to finish, but this time for t2. Once it has finished, the main thread is unblocked and continues.

Explanation 5

The main thread has begun t3s execution, and immediately waited for it to complete.

Summary

Overall, this example application yields indeterminate results. There is no way of knowing when the execution of t1->t3 will occur. Having differing results is normal because the threads may get different CPU time each run causing them to progress farther or less far in their logic blocks. What we do know is that the main thread will ensure that t1 and t2 has finished before starting t3. Also that all threads t1->t3 will finish execution before the main thread finishes.

Upvotes: 2

Related Questions