Java thread synchronization

This article talks about the importance of thread synchronization in Java and how you can implement it in your programs.

When your program has multiple threads, problems may arise when different threads try to access the same resource or perform the same actions concurrently. This type of situation gives rise to errors and concurrency issues. Let us take an example where there are two threads in your program trying to read/write a text file. When the file is being written on by both the threads, one thread’s data might be over written by the other thread and the same issue can be found when the file is being read.

Hence thread synchronization is necessary such that multiple threads access the same resources one thread at a time in any give point of time.

Why to use thread synchronization?

  • Prevent thread interference
  • Avoid consistency problem and concurrency issues
  • Prevent data loss




There are two types of thread synchronization mutual exclusive and inter-thread communication.

  • Mutual Exclusive
  • Synchronized method.
  • Synchronized block.
  • Static synchronization.
  • Cooperation (Inter-thread communication in java)

 

Synchronized block

Synchronized blocks are used for thread synchronization.

Synchronized keyword is used to identify a synchronized block in Java and is synchronized based on some object. The main concept behind this is that all synchronized blocks synchronized on the same object can only have one thread executing inside them at a time which prevents multiple threads running and executing concurrently. All other threads attempting to enter the synchronized block are blocked until the thread inside the synchronized block exits the block.

Shared resources are kept within this synchronized block such that only one thread can access a particular resource at a given point of time.

Syntax for a synchronized block is shown below:

synchronized(referencetoobject) {
   // Shared variables and other shared resources are placed here
}

Monitors

The concept of Monitors is important while trying to understand and implementing synchronization in Java.

  • Each object in Java is associated with a monitor
  • A thread can lock or unlock a monitor
  • Only one thread can own a monitor at a given time.
  • Only one thread at a time may hold a lock on a monitor

 

Thread Synchronization Example

//We write a program with a simple counter execution.
class Countings {
   public void printing() {
      try {
         for(int i = 5; i > 0; i--) {
            System.out.println( i );
         }
      } catch (Exception e) {
         System.out.println("Thread  interrupted.");
      }
   }
}

class Threadings extends Thread {
   private Thread thrd;
   private String thrdName;
   Countings gg;

   Threadings( String name,  Countings abc) {
      thrdName = name;
      gg = abc;
   }
    public void run() {
      gg.printing();
      System.out.println("Thread " +  thrdName + " exiting.");
   }

   public void start () {
      System.out.println("Starting " +  thrdName );
      if (thrd == null) {
         thrd = new Thread (this, thrdName);
         thrd.start ();
      }
   }
}

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

      Countings gg = new Countings();

      Countings T1 = new Countings ( "Thread - 1 ", gg );
      Countings T2 = new Countings ( "Thread - 2 ", gg );

      T1.start();
      T2.start();

      // threads take some time to end
         try {
         T1.join();
         T2.join();
      } catch ( Exception e) {
         System.out.println("Interrupted");
      }
   }
}

 

Output: (Produces a different result with each run)

Starting Thread - 1
Starting Thread - 2
5
4
3
5
2
1
4
Thread Thread - 1  exiting.
3
2
1
Thread Thread - 2  exiting.

 

The same example but this time with thread synchronization:

class Countings {
   public void printings() {
      try {
         for(int i = 5; i > 0; i--) {
            System.out.println( i );
         }
      } catch (Exception e) {
         System.out.println("Thread  interrupted.");
      }
   }
}
class Threadings extends Thread {
   private Thread t;
   private String thrdName;
   Countings  gg;

   Threadings( String name,  Countings abc) {
      thrdName = name;
      gg = abc;
   }
   
   public void run() {
      synchronized(gg) {
         gg.printings();
      }
      System.out.println("Thread " +  threadName + " exiting.");
   }

   public void start () {
      System.out.println("Starting " +  thrdName );
      if (thrd == null) {
         thrd = new Thread (this, thrdName);
         thrd.start ();
      }
   }
}

public class Testings{

   public static void main(String args[]) {
      Countings gg = new Countings();

      Threadings T1 = new Threadings ( "Thread - 1 ", gg );
      Threadings T2 = new Threadings ( "Thread - 2 ", gg );

      T1.start();
      T2.start();

      // wait for threads to end
      try {
         T1.join();
         T2.join();
      } catch ( Exception e) {
         System.out.println("Interrupted");
      }
   }
}

 

Output: (We can see the output is synchronized and is the same every time we execute the program)

Starting Thread - 1
Starting Thread - 2
5
4
3
2
1
Thread Thread - 1  exiting.
5
4
3
2
1
Thread Thread - 2  exiting.

 

Leave a Reply

avatar