Synchronized Keyword in Java

Introduction to Synchronized Methods for Threads in Java

Synchronized methods are a convenient way to synchronize access to shared data in Java. A synchronized method is a method that is protected by a lock. Only one thread can execute a synchronized method at a time.

To create a synchronized method, you use the `synchronized` keyword. You can specify the object that the method is synchronized on. If you do not specify an object, the method is synchronized on the current object.

Here is an example of a synchronized method:



  public class Counter {
      private int count;

      public synchronized int get() {
          return count;
      }

      public synchronized void increment() {
          count++;
      }
  }
  

This code ensures that only one thread can access the `count` variable at a time. If two or more threads try to increment the counter at the same time, the threads will be serialized, meaning that they will execute one at a time.

Synchronized methods are a good way to synchronize access to shared data because they are easy to use and understand. However, it is important to note that synchronized methods can reduce the performance of your application. This is because only one thread can execute a synchronized method at a time.

Here are some tips for using synchronized methods effectively:

  • Only synchronize the methods that need to be synchronized. Synchronizing too many methods can reduce the performance of your application.
  • Be careful not to create deadlocks. A deadlock occurs when two or more threads are waiting for each other to finish executing before they can continue. To avoid deadlocks, follow the rules of lock acquisition and release.
  • Use a lock hierarchy. A lock hierarchy is a way of organizing locks to reduce the risk of deadlocks.

Synchronized methods are a powerful tool, but they must be used carefully to avoid performance problems and deadlocks. By following the tips above, you can help to ensure that you are using synchronized methods effectively.

In addition to the above, here are some additional benefits of using synchronized methods:

  • Synchronized methods are easy to use and understand.
  • Synchronized methods are thread-safe, meaning that they can be safely used by multiple threads at the same time.
  • Synchronized methods are portable, meaning that they can be used on different platforms.

Overall, synchronized methods are a good choice for synchronizing access to shared data in Java. However, it is important to use them carefully to avoid performance problems and deadlocks.

Exercises

Code for demonstrating Synchronized keyword in Threads. The withdraw method is a synchronized method and will allow only one Thread to access it at any point.


package sampleproject;
import java.util.*;
import java.io.*;
public class democlass{	
public static void main(String[] args) throws InterruptedException {	

  account satish = new account();
  Thread trans1 = new Thread(new Runnable() {
    
    @Override
    public void run() {
      for(int i=0;i<500;i++)
      {
        satish.withdraw(10);
      }
    }
  });
  Thread trans2 = new Thread(new Runnable() {
    
    @Override
    public void run() {
      for(int i=0;i<500;i++)
      {
        satish.withdraw(10);
      }
    }
  });
  trans1.start();
  trans2.start();
  trans1.join();
  trans2.join();
  satish.getbalance();
}
}

class account
{
private int balance;
public account() {
  // TODO Auto-generated constructor stub
this.balance=20000;
}
public synchronized void withdraw(int withdraw_amount) {
  this.balance=this.balance-withdraw_amount;
}
public void getbalance() {
  System.out.println(this.balance);
}
}  

Code for demonstrating static Synchronized with Threads. The withdraw method is a synchronized method and will allow only one Thread to access it at any point


  package sampleproject;
  import java.util.*;
  import java.io.*;
  public class democlass{	
    
    public static void main(String[] args) throws InterruptedException{
      
      
      Thread thr1 = new Thread(new Runnable() {
        
        @Override
        public void run() {
          try {
            test.method1();
          } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
          }
          
        }
      });
      Thread thr2 = new Thread(new Runnable() {
        
        @Override
        public void run() {
          try {
            test.method1();
          } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
          }
        }
      });
      
      thr1.start();
      thr2.start();
      
    }	
  }
  class test
  {
      
    public static synchronized void method1() throws InterruptedException{
        {
          System.out.println("common for all objects");
          Thread.currentThread().sleep(9000);
        }
      }			
  }