CodingBison

With multiple threads, it is possible that one or more of them may end up accessing a common data (aka critical data) in the memory. If that happens, then we need to synchronize threads. Informally, synchronization means deciding which thread gets to access critical data first. All other threads simply need to play the waiting game; more specifically, these threads sit in the blocked state.

Java threads achieve synchronization using monitor (A monitor is not a mutex but for simplicity sake we can consider it to be a kind of mutex, short for mutual exclusion). The easiest way to understand a monitor is to understand it as a lock such that only one thread can lock (or acquire) it at a given time. The thread that acquires the lock, gets to access the common data. In the meantime, all other threads simply wait for their turn. Once the thread with the lock is done accessing data, it can unlock the monitor. With that, one of the waiting threads will acquire the lock and access the data. And, thus the cycle of wait for monitor, lock monitor, access critical data, and unlock monitor continues. It is common to use the terms "lock a monitor" and "acquire a monitor" interchangeably.

Other popular programming languages like C, synchronization between threads is done by using the elements like, semaphores or locks or mutex that are provided by the operating system. The user have to take the responsibility of using those element carefully to achieve thread synchronization. Java, on the other had a method called "synchronized" which does all of it. All the user has to do is to guard the code block with this method. Let us look at an example to understand the concept of synchronized.



Figure: Thread Synchronization

 class commonClass {
     public void commonFunction(String threadName) {
         System.out.println("\t[Synchronized] Common function called by " + threadName );
         try {
             Thread.sleep(100);
         } catch (InterruptedException e) {
             // TODO Auto-generated catch block
             e.printStackTrace();
         }
         System.out.println("\t[Synchronized] " + threadName + " Finished execution" );
     }
 }

 class sampleThread implements Runnable {
     Thread thread;
     commonClass commonClassObj;

     sampleThread(String threadName,commonClass obj) {
         commonClassObj = obj;
         thread = new Thread(this, threadName);
         thread.setName(threadName);
         thread.start();
     }

     @Override
     public void run() {
         synchronized(commonClassObj) {
             commonClassObj.commonFunction(thread.getName());
             System.out.println(" Exiting the RUN method, Thread " + thread.getName());
         }
     }
 }

 public class multiThreadingExample {
     public static void main(String[] args) {
         System.out.println(" Main Thread Starts.... ");
         commonClass commonClassObj = new commonClass();
         sampleThread skyfallThread = new sampleThread("Skyfall", commonClassObj);
         sampleThread CasinoRoyalThread = new sampleThread("Casino Royal", commonClassObj);

         System.out.println(" Main Thread Exits ");
     }
 }

Every object will have its own internal monitor, which will be used by the synchronize method to achieve thread synchronization. The above program has 2 threads trying to access the Same "commonClassObj". Synchronization among the threads is achieved by using "synchronized" method. All the complex tasks of waiting for the lock, acquiring the lock, releasing the lock etc is automatically taken care by the synchronized method itself. Like shown in the above figure, skyfall thread acquires the Monitor for the commonClassObj finishes the execution of the common block and then releases the Monitor. While skyfall thread has the monitor, casinoRoyal thread is also trying to execute the same block of code, it cannot do that since it does not have the monitor for the "commonClassObj", so it waits for the skyfall thread to release the monitor.

Let us examine the output of the above program. Notice that, the casinoRoyalThread started with common block only after skyfallThread finished executing the common block of code. There is no race condition between the 2 threads.

  Main Thread Starts.... 
 	[Synchronized] Common function called by Skyfall
  Main Thread Exits 
 	[Synchronized] Skyfall Finished execution
  Exiting the RUN method, Thread Skyfall
 	[Synchronized] Common function called by Casino Royal
 	[Synchronized] Casino Royal Finished execution
  Exiting the RUN method, Thread Casino Royal

Let us remove the synchronized statement and notice both the threads executing the common block at the same time. In the real time scenarios, this leads to many issues including deadlocks.

  Main Thread Starts.... 
  Main Thread Exits 
 	[Synchronized] Common function called by Skyfall
 	[Synchronized] Common function called by Casino Royal
 	[Synchronized] Casino Royal Finished execution
  Exiting the RUN method, Thread Casino Royal
 	[Synchronized] Skyfall Finished execution
  Exiting the RUN method, Thread Skyfall

Inter-thread Communication

Java provides support for inter thread communication, this is important when we have 2 threads trying to communicate with each other. The earlier example which synchronized() method, makes the threads wait for the monitor unconditionally. Java provides some APIs through which two threads can communicate with each other.

 wait() - This makes the current thread to wait for another thread to notify() it. This API will force the current
 thread to give up the monitor and go to sleep state.

 notify() - Wakes up the first thread in the list that went to sleep state.

 notifyAll() - Wakes up all the threads that are in sleep state.




comments powered by Disqus