Java Multithreading concept and join() method
Asked Answered
G

12

59

I'm confused in join() method used in Threads in Java. In the following code:

// Using join() to wait for threads to finish.
class NewThread implements Runnable {

    String name; // name of thread
    Thread t;

    NewThread(String threadname) {
        name = threadname;
        t = new Thread(this, name);
        System.out.println("New thread: " + t);
        t.start(); // Start the thread
    }
// This is the entry point for thread.

    public void run() {
        try {
            for (int i = 5; i > 0; i--) {
                System.out.println(name + ": " + i);
                Thread.sleep(1000);
            }
        } catch (InterruptedException e) {
            System.out.println(name + " interrupted.");
        }
        System.out.println(name + " exiting.");
    }
}

class DemoJoin {

    public static void main(String args[]) {
        NewThread ob1 = new NewThread("One");
        NewThread ob2 = new NewThread("Two");
        NewThread ob3 = new NewThread("Three");
        System.out.println("Thread One is alive: "
                + ob1.t.isAlive());
        System.out.println("Thread Two is alive: "
                + ob2.t.isAlive());
        System.out.println("Thread Three is alive: "
                + ob3.t.isAlive());
// wait for threads to finish
        try {
            System.out.println("Waiting for threads to finish.");
            ob1.t.join();
            ob2.t.join();
            ob3.t.join();
        } catch (InterruptedException e) {
            System.out.println("Main thread Interrupted");
        }
        System.out.println("Thread One is alive: "
                + ob1.t.isAlive());
        System.out.println("Thread Two is alive: "
                + ob2.t.isAlive());
        System.out.println("Thread Three is alive: "
                + ob3.t.isAlive());
        System.out.println("Main thread exiting.");
    }
}

Sample output from this program is shown here:

New thread: Thread[One,5,main]
New thread: Thread[Two,5,main]
New thread: Thread[Three,5,main]
Thread One is alive: true
Thread Two is alive: true
Thread Three is alive: true
Waiting for threads to finish.
One: 5
Two: 5
Three: 5
One: 4
Two: 4
Three: 4
One: 3
Two: 3
Three: 3
One: 2
Two: 2
Three: 2
One: 1
Two: 1
Three: 1
Two exiting.
Three exiting.
One exiting.
Thread One is alive: false
Thread Two is alive: false
Thread Three is alive: false
Main thread Exiting

In the above code :

  1. I'm not able to understand the flow of execution of the program, And when ob1 is created then the constructor is called where t.start() is written but still run() method is not executed rather main() method continues execution. So why is this happening?

  2. join() method is used to wait until the thread on which it is called does not terminates, but here in output we see alternate outputs of the thread why??

And if the use of join is this then what is the use of synchronized??

I know I'm missing a basic concept here, but I'm not able to figure it out so please help.

Gore answered 28/8, 2013 at 5:0 Comment(4)
'I'm not able to understand the flow of execution of the program' - OK, that's normal with multithreading. The trick is to design so that it does not matter.Bara
You must run this program in debug mode, you will better understand the concept of join(). Actually it's hard to predict the correct order. So run it in debug mode.Hemstitch
calling start from constructor is a bad idea, the object may not have been well formed yet.Bateman
Think of it as blocking parallel execution. Any subsequent statements will only run after the joined threads are doneResupinate
M
167

You must understand , threads scheduling is controlled by thread scheduler.So, you cannot guarantee the order of execution of threads under normal circumstances.

However, you can use join() to wait for a thread to complete its work.

For example, in your case

ob1.t.join();

This statement will not return until thread t has finished running.

Try this,

class Demo {
   Thread t = new Thread(
                 new Runnable() {
                     public void run () {
                         //do something
                     }
                  }
    );
    Thread t1 = new Thread(
                 new Runnable() {
                     public void run () {
                         //do something
                     }
                  }
    );
    t.start(); // Line 15
    t.join();  // Line 16
    t1.start();
}

In the above example, your main thread is executing. When it encounters line 15, thread t is available at thread scheduler. As soon as main thread comes to line 16, it will wait for thread t to finish.

NOTE that t.join did not do anything to thread t or to thread t1. It only affected the thread that called it (i.e., the main() thread).

Edited:

t.join(); needs to be inside the try block because it throws the InterruptedException exception, otherwise you will get an error at compile time. So, it should be:

try{
    t.join();
}catch(InterruptedException e){
    // ...
}
Male answered 28/8, 2013 at 5:51 Comment(8)
I have searched online for a simple answer that will explain this concept in a SIMPLE WAY!! for almost an hour. but this is the only answer i have found that went straight to the point, in the simplest way. @malwaregeek, Thankyou.Grimm
What happens if t.join() is removed(Line 16) and t1.join is added after t1.start()?Troup
if the calling threads enters sleep mode will the current thread execute?Granger
@Male will the main thread get executed again after the t1 thread goes to wait state. or it will run only after the thread t1 completely executedAgrippina
What I don't understand is what is the current thread, when there are two running threads? Since line 15 you have both t andmain running. When you say join() in line 16, the current thread is to be stopped, but it was t that started last. And what about when you have 3 threads running after line 17? Which one is the current one?Pyrethrin
Confused about that whether t1.start() since t1 is started using main thread it should not start unless t thread is over since we are using t.join.Neomaneomah
I edited this answer to remove the words "current thread." Whenever you see those words in documentation, they are not talking about the currently running thread!! (Which thread would that be in a program that has many threads running on a multi-core machine?) "Current thread" really means "the thread that is calling the function." Thread.currentThread() returns a reference to the Thread object that controls the caller. Thread.sleep(n) is just a function that waits for n milliseconds before returning, t.join() is just a function that waits for thread t to die, etc.Barratry
what happens if i use t.join() after t1.start()?Matisse
S
6

First of all, when you create ob1 then constructor is called and it starts execution. At that time t.start() also runs in separate thread. Remember when a new thread is created, it runs parallely to main thread. And thats why main start execution again with next statement.

And Join() statement is used to prevent the child thread from becoming orphan. Means if you did'nt call join() in your main class, then main thread will exit after its execution and child thread will be still there executing the statements. Join() will wait until all child thread complete its execution and then only main method will exit.

Go through this article, helps a lot.

Shot answered 28/8, 2013 at 5:13 Comment(2)
So it means if there is no join() then "One Two Three... " output part wont come ??Gore
no..its not that. Its shows the output of Ont two three.. but in middle of one two three..Main Thread Existing will be shown because main thread completes its execution and it has nothing to do with child thread.Shot
T
4

I'm not able to understand the flow of execution of the program, And when ob1 is created then the constructor is called where t.start() is written but still run() method is not executed rather main() method continues execution. So why is this happening?

This depends on Thread Scheduler as main shares the same priority order. Calling start() doesn't mean run() will be called immediately, it depends on thread scheduler when it chooses to run your thread.

join() method is used to wait until the thread on which it is called does not terminates, but here in output we see alternate outputs of the thread why??

This is because of the Thread.sleep(1000) in your code. Remove that line and you will see ob1 finishes before ob2 which in turn finishes before ob3 (as expected with join()). Having said that it all depends on when ob1 ob2 and ob3 started. Calling sleep will pause thread execution for >= 1 second (in your code), giving scheduler a chance to call other threads waiting (same priority).

Tipstaff answered 25/2, 2014 at 6:23 Comment(0)
P
2

I came across the join() while learning about race condition and I will clear the doubts I was having. So let us take this small example

Thread t2 = new Thread(
             new Runnable() {
                 public void run () {
                     //do something
                 }
              }
);
Thread t1 = new Thread(
             new Runnable() {
                 public void run () {
                     //do something
                 }
              }
);
t2.start(); //Line 11
t1.start(); //Line 12
t2.join();  //Line 13
t1.join();  //Line 14
System.out.print("<Want to print something that was being modified by t2 and t1>")

My AIM
Three threads are running namely t1, t2 and the main thread. I want to print something after the t1 and t2 has finished. The printing operation is on my main thread therefore for the expected answer I need to let t1 and t2 finish and then print my output.

So t1.join() just makes the main thread wait, till the t1 thread completes before going to the next line in program.

Here is the definition as per GeeksforGeeks:

java.lang.Thread class provides the join() method which allows one thread to wait until another thread completes its execution.

Here is one question that might solve your doubt

Q-> Will t1 thread get the time slice to run by the thread scheduler, when the program is processing the t2.join() at Line 13?

ANS-> Yes it will be eligible to get the time slice to run as we have already made it eligible by running the line t1.start() at Line 11.
t2.join() only applies the condition when the JVM will go to next line, that is Line 14.
It might be also possible that t1 might get finished processing at Line 13.

Pyonephritis answered 17/9, 2018 at 13:31 Comment(0)
M
1

First rule of threading - "Threading is fun"...

I'm not able to understand the flow of execution of the program, And when ob1 is created then the constructor is called where t.start() is written but still run() method is not executed rather main() method continues execution. So why is this happening?

This is exactly what should happen. When you call Thread#start, the thread is created and schedule for execution, it might happen immediately (or close enough to it), it might not. It comes down to the thread scheduler.

This comes down to how the thread execution is scheduled and what else is going on in the system. Typically, each thread will be given a small amount of time to execute before it is put back to "sleep" and another thread is allowed to execute (obviously in multiple processor environments, more than one thread can be running at time, but let's try and keep it simple ;))

Threads may also yield execution, allow other threads in the system to have chance to execute.

You could try

NewThread(String threadname) {
    name = threadname;
    t = new Thread(this, name);
    System.out.println("New thread: " + t);
    t.start(); // Start the thread
    // Yield here
    Thread.yield();
}

And it might make a difference to the way the threads run...equally, you could sleep for a small period of time, but this could cause your thread to be overlooked for execution for a period of cycles (sometimes you want this, sometimes you don't)...

join() method is used to wait until the thread on which it is called does not terminates, but here in output we see alternate outputs of the thread why??

The way you've stated the question is wrong...join will wait for the Thread it is called on to die before returning. For example, if you depending on the result of a Thread, you could use join to know when the Thread has ended before trying to retrieve it's result.

Equally, you could poll the thread, but this will eat CPU cycles that could be better used by the Thread instead...

Mcmillin answered 28/8, 2013 at 5:14 Comment(1)
Basically. It would require a loop, that would periodically check to see if the thread had competed or not. May it would use yield or sleep. But this would require the thread to have time to execute, taking time away from other threadsMcmillin
B
1

The JVM and the underlying OS have considerable freedom when scheduling things. The fact that you get all the way to "Waiting for threads to finish" before you see the output from individual threads may simply mean that thread start-up takes a bit longer (i.e. it takes some time between the moment when a thread becomes "alive" and when the run() method actually starts executing). You could conceivably see thread output sooner but it's not guaranteed either way.

As for join(), it only guarantees that whatever is after it will only happen once the thread you are joining is done. So when you have three join() calls in a row it doesn't mean the threads should end in a particular order. It simply means that you will wait for ob1 first. Once ob1 finishes, ob2 and ob3 may be still running or they may already be finished. If they are finished, your other join() calls will return immediately.

synchronized is used specifically when multiple threads access the same object and make changes to it. A synchronized block is guaranteed never to be executed by two threads simultaneously - i.e. the thread that executes it has the synchronized object all to itself.

Benedicto answered 28/8, 2013 at 5:22 Comment(0)
S
1

when ob1 is created then the constructor is called where "t.start()" is written but still run() method is not executed rather main() method is executed further. So why is this happening?

here your threads and main thread has equal priority.Execution of equal priority thread totally depends on the Thread schedular.You can't expect which to execute first.

join() method is used to wait until the thread on which it is called does not terminates, but here in output we see alternate outputs of the thread why??

Here your calling below statements from main thread.

     ob1.t.join();
     ob2.t.join();
     ob3.t.join();

So main thread waits for ob1.t,ob2.t,ob3.t threads to die(look into Thread#join doc).So all three threads executes successfully and main thread completes after that

Soft answered 28/8, 2013 at 5:22 Comment(0)
C
1

My Comments:

When I see the output, the output is mixed with One, Two, Three which are the thread names and they run simultaneously. I am not sure when you say thread is not running by main method.

Not sure if I understood your question or not. But I m putting my answer what I could understand, hope it can help you.

1) Then you created the object, it called the constructor, in construct it has start method which started the thread and executed the contents written inside run() method.

So as you created 3 objects (3 threads - one, two, three), all 3 threads started executing simultaneously.

2) Join and Synchronization They are 2 different things, Synchronization is when there are multiple threads sharing a common resource and one thread should use that resource at a time. E.g. Threads such as DepositThread, WithdrawThread etc. do share a common object as BankObject. So while DepositThread is running, the WithdrawThread will wait if they are synchronized. wait(), notify(), notifyAll() are used for inter-thread communication. Plz google to know more.

about Join(), it is when multiple threads are running, but you join. e.g. if there are two thread t1 and t2 and in multi-thread env they run, the output would be: t1-0 t2-0 t1-1 t2-1 t1-2 t2-2

and we use t1.join(), it would be: t1-0 t1-1 t1-2 t2-0 t2-1 t2-2

This is used in realtime when sometimes you don't mix up the thread in certain conditions and one depends another to be completed (not in shared resource), so you can call the join() method.

Contorted answered 28/8, 2013 at 5:35 Comment(3)
Ok, But when t.start() is encountered during constructor execution run() method is not executed instead the main thread is executed...why does this happen??Gore
Can you tell me what exactly do you mean main thread? Why do you think run() method is not executed?Contorted
I mean the main() function which is the current thread, and I don't say that run method does not run at all I mean why it does not run when t.start() is encountered... well I guess I got its answers in the following posts!Gore
S
1

No words just running code

// Thread class
public class MyThread extends Thread {

    String result = null;

    public MyThread(String name) {
        super(name);
    }

    public void run() {
        for (int i = 0; i < 1000; i++) {

            System.out.println("Hello from " + this.getName());
        }
        result = "Bye from " + this.getName();
    }
}

Main Class

public class JoinRND {
    public static void main(String[] args) {

        System.out.println("Show time");
        // Creating threads
        MyThread m1 = new MyThread("Thread M1");
        MyThread m2 = new MyThread("Thread M2");
        MyThread m3 = new MyThread("Thread M3");

        // Starting out Threads
        m1.start();
        m2.start();
        m3.start();
        // Just checking current value of thread class variable
        System.out.println("M1 before: " + m1.result);
        System.out.println("M2 before: " + m2.result);
        System.out.println("M3 before: " + m3.result);
        // After starting all threads main is performing its own logic in
        // parallel to other threads
        for (int i = 0; i < 1000; i++) {

            System.out.println("Hello from Main");
        }

        try {

            System.out
                    .println("Main is waiting for other threads to get there task completed");
            m1.join();
            m2.join();
            m3.join();
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        System.out.println("M1 after" + m1.result);
        System.out.println("M2 after" + m2.result);
        System.out.println("M3 after" + m3.result);

        System.out.println("Show over");
    }
}
Saddlery answered 26/4, 2017 at 8:1 Comment(0)
R
1

Thread scheduler is responsible for scheduling of threads. So every time you run the program, there is no guarantee to the order of execution of threads. Suppose you have a thread object named threadOne and if join() is called on threadOne like this:

threadOne.join()

then all currently executing threads will be paused until thread1 has finished its execution or terminates.

Consider the following piece of code:

class RunnableSample implements Runnable {
    private Thread t;
    private String threadName;

    public RunnableSample(String name) {
        this.threadName = name;
    }
    public void run() {
        try {
            for(int i = 4; i >= 1; i--) {
                System.out.println(Thread.currentThread().getName() + ", " + i);
            Thread.sleep(500);
            }
        } catch (InterruptedException e) {
            System.out.println(threadName + " interrupted");
        }
    }
    public void start() {
        if(t == null)
            t = new Thread(this, threadName);
        t.start();
        try {
            t.join();
        } catch(Exception e) {
            System.out.println(e);
        }
    }
}
public class RunnableDemo {
    public static void main(String[] args) {
        RunnableSample r1 = new RunnableSample("threadOne");
        r1.start();

        RunnableSample r2 = new RunnableSample("threadTwo");
        r2.start();

        RunnableSample r3 = new RunnableSample("threadThree");
        r3.start();
     }
}

The output of the above program will be:

threadOne, 4
threadOne, 3
threadOne, 2
threadOne, 1
threadTwo, 4
threadTwo, 3
threadTwo, 2
threadTwo, 1
threadThree, 4
threadThree, 3
threadThree, 2
threadThree, 1

Since join() is called on threadOne first, threadTwo and threadThree will be paused until threadOne terminates. (NOTE that threadOne, threadTwo and ThreadThree all have started). Now the threads are executing in a specific order. If join() is not called on a thread in our example, then there will be no order of execution of threads.

public void start() {
    if(t == null)
        t = new Thread(this, threadName);
    t.start();
}

Its output will be:

threadOne, 4
threadThree, 4
threadTwo, 4
threadTwo, 3
threadThree, 3
threadOne, 3
threadOne, 2
threadThree, 2
threadTwo, 2
threadOne, 1
threadThree, 1
threadTwo, 1

Coming to synchronization, which is useful if you want to control the access of multiple threads on any shared resource. If you want to restrict only one thread to access shared resources then synchronization is the best way to do it.

Rhondarhondda answered 15/6, 2017 at 4:46 Comment(0)
W
0

join() is a instance method of java.lang.Thread class which we can use join() method to ensure all threads that started from main must end in order in which they started and also main should end in last. In other words waits for this thread to die.

Exception: join() method throws InterruptedException.

Thread state: When join() method is called on thread it goes from running to waiting state. And wait for thread to die.

synchronized block: Thread need not to acquire object lock before calling join() method i.e. join() method can be called from outside synchronized block.

Waiting time: join(): Waits for this thread to die.

public final void join() throws InterruptedException;

This method internally calls join(0). And timeout of 0 means to wait forever;

join(long millis) – synchronized method Waits at most millis milliseconds for this thread to die. A timeout of 0 means to wait forever.

public final synchronized void join(long millis)
    throws InterruptedException;

public final synchronized void join(long millis, int nanos)
    throws InterruptedException;

Example of join method

class MyThread implements Runnable {
     public void run() {
           String threadName = Thread.currentThread().getName();
           Printer.print("run() method of "+threadName);
           for(int i=0;i<4;i++){
                Printer.print("i="+i+" ,Thread="+threadName);
           }         
     }
}

public class TestJoin {
     public static void main(String...args) throws InterruptedException {
           Printer.print("start main()...");

           MyThread runnable = new MyThread();
           Thread thread1=new Thread(runnable);
           Thread thread2=new Thread(runnable);

           thread1.start();
           thread1.join();

           thread2.start();
           thread2.join();

           Printer.print("end main()");
     }
}

class Printer {
     public static void print(String str) {
           System.out.println(str);
     }
}

Output:
     start main()...
     run() method of Thread-0
     i=0 ,Thread=Thread-0
     i=1 ,Thread=Thread-0
     i=2 ,Thread=Thread-0
     i=3 ,Thread=Thread-0
     run() method of Thread-1
     i=0 ,Thread=Thread-1
     i=1 ,Thread=Thread-1
     i=2 ,Thread=Thread-1
     i=3 ,Thread=Thread-1
     end main()

Note: calling thread1.join() made main thread to wait until Thread-1 dies.

Let’s check a program to use join(long millis)

First, join(1000) will be called on Thread-1, but once 1000 millisec are up, main thread can resume and start thread2 (main thread won’t wait for Thread-1 to die).

class MyThread implements Runnable {
     public void run() {
           String threadName = Thread.currentThread().getName();
           Printer.print("run() method of "+threadName);
           for(int i=0;i<4;i++){
                try {
                     Thread.sleep(500);
                } catch (InterruptedException e) {
                     e.printStackTrace();
                }
                Printer.print("i="+i+" ,Thread="+threadName);
           }         
     }
}

public class TestJoin {
     public static void main(String...args) throws InterruptedException {
           Printer.print("start main()...");

           MyThread runnable = new MyThread();
           Thread thread1=new Thread(runnable);
           Thread thread2=new Thread(runnable);

           thread1.start();

           // once 1000 millisec are up,
           // main thread can resume and start thread2.
           thread1.join(1000);

           thread2.start();
           thread2.join();

           Printer.print("end main()");
     }
}

class Printer {
     public static void print(String str) {
           System.out.println(str);
     }
}

Output:
     start main()...
     run() method of Thread-0
     i=0 ,Thread=Thread-0
     run() method of Thread-1
     i=1 ,Thread=Thread-0
     i=2 ,Thread=Thread-0
     i=0 ,Thread=Thread-1
     i=1 ,Thread=Thread-1
     i=3 ,Thread=Thread-0
     i=2 ,Thread=Thread-1
     i=3 ,Thread=Thread-1
     end main()

For more information see my blog:

http://javaexplorer03.blogspot.in/2016/05/join-method-in-java.html

Whiteheaded answered 12/5, 2016 at 4:6 Comment(0)
H
0

See the concept is very simple.

1) All threads are started in the constructor and thus are in ready to run state. Main is already the running thread.

2) Now you called the t1.join(). Here what happens is that the main thread gets knotted behind the t1 thread. So you can imagine a longer thread with main attached to the lower end of t1.

3) Now there are three threads which could run: t2, t3 and combined thread(t1 + main).

4)Now since till t1 is finished main can't run. so the execution of the other two join statements has been stopped.

5) So the scheduler now decides which of the above mentioned(in point 3) threads run which explains the output.

Hygrometric answered 10/12, 2018 at 21:48 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.