Reputation: 1189
I'm confused by the join()
method used with threads in Java. Consider 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:
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 the run()
method is not executed, rather the main()
method continues execution. So why is this happening?
The join()
method is used to wait until the thread on which it is called does not terminate, but here in the 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.
Upvotes: 59
Views: 122831
Reputation: 2274
You must understand, threads scheduling is controlled by a 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 for the thread scheduler. As soon as the 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 may throw an InterruptedException
, otherwise you will get an error at compile time. So, it should be:
try{
t.join();
}catch(InterruptedException e){
// ...
}
Upvotes: 166
Reputation: 556
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.
Upvotes: 0
Reputation: 2769
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.
Upvotes: 2
Reputation: 11
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");
}
}
Upvotes: 1
Reputation: 279
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:
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.
Upvotes: 1
Reputation: 49
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).
Upvotes: 4
Reputation: 10497
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.
Upvotes: 6
Reputation:
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.
Upvotes: 1
Reputation: 8473
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
Upvotes: 1
Reputation: 121
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.
Upvotes: 1
Reputation: 347244
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 stillrun()
method is not executed rathermain()
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...
Upvotes: 1