Baran Topal

Baran Topal


May 2024
M T W T F S S
« Feb    
 12345
6789101112
13141516171819
20212223242526
2728293031  

Categories


Multithreading and join in Java

baranbaran

It is always the case i forgot how multithreading mechanism works in Java. Multithreading is not a thing that I do everyday 🙂

“join()” simply halts the “calling” thread and waits until the thread that join() is called on finishes.

When it does finish, the “calling” thread resumes execution at the next statement. Let me draw a dodgy ASCII art picture of this (and it might not look correct on your phone).

Main Thread |-------1--2----3       5------>
New Thread          |   -----------4

1. The main thread creates a “new Thread()” object.
2. The main thread calls “.start()” on the new thread
(Note: that BOTH threads are running simultaneously now)
3. The main thread calls “.join()” on the new thread. As you can see, the main thread now stops executing code, and it waits until the new thread has finished. (Note: It doesn’t affect the new thread in *any* way.)
4. The new thread finished execution, maybe because all the work it had to do has been done. (Note: This is not because .join() was called. This is just the *normal* end of the thread processing)
5. Since the new thread has finished, the “.join()” call returns and the main thread continues processing at the next instruction.

(Note: the other variation to this, is if the main thread calls .join() AFTER that new thread has already finished. If that happens, the .join() call simply returns immediately and the main thread continues processing)

An example is as follows:

class CallMe
{
 void call(String msg)
 { 
 System.out.println("[" + msg);
 try
 {
 Thread.sleep(1000);
 }
 catch(Exception ex)
 {
 System.out.println("Interrupted");
 }
 System.out.println("]");
 }
}


class Caller implements Runnable
{
 String msg;
 CallMe target;
 Thread t;
 public Caller(CallMe target, String s)
 {
 this.target = target;
 msg = s;
 t = new Thread(this);
 t.start();
 }

 @Override
 public void run()
 {
 synchronized(target)
 {
 target.call(msg);
 }
 }
}

public class Synch {

 /**
 * @param args
 */
 public static void main(String[] args) {
 // TODO Auto-generated method stub
 CallMe target = new CallMe();
 Caller ob1 = new Caller(target, "Hello");
 Caller ob2 = new Caller(target, "Synchronized");
 Caller ob3 = new Caller(target, "World");

 try
 {
 ob1.t.join();
 ob2.t.join(); 
 ob3.t.join(); 
 }
 catch(Exception ex)
 {
 System.out.println("Interrupted");
 } 
 }
}

All the synchronized block is doing here, is to ensure that no other thread can call “target.call(msg)” if it is already being executed. There is nothing in above code to ensure the *order* that “target.call(msg)” methods are called. Even though i am creating the 3 threads in a certain order, due to the way multithreading works, that won’t mean that they 3 threads will get to run in that order. Also, the order of the 3 “join()” calls has no effect on the order either. All they do is tell the main thread to *wait* until the target thread has finished execute, it doesn’t force any particular thread to finish first or anything like that. The only way to guarantee the running order of those 3 threads is to do the following:

CallMe target = new CallMe();
Caller ob1 = new Caller(target, "Hello");
ob1.t.join();
Caller ob2 = new Caller(target, "Synchronized");
ob2.t.join();
Caller ob3 = new Caller(target, "World"); 
ob3.t.join();

 
The whole idea of multithreading is so that the 3 tasks DON’T run sequentially, ie. that they can run at the same time. Yes, I know that at times you need to have exclusive access to resources (which is exactly what synchronized is for) but if your program requirement was for sequential, exclusive, guaranteed order, then single threaded programming is exactly what you need.