Java Synchronized Blocks and Methods

We can create synchronized (thread safe) blocks and methods in Java using the synchronized keyword. The method or block marked as synchronized can be accessed a single thread at a time.

What is the need for syncrhonized blocks and methods in Java?

In multithreaded environments, sometimes two threads access the same method or another code block simultaneously, which can lead to an issue.

Imagine a method that first checks if the record is present in DB. If not, it saves it. Otherwise, it ignores it.

Now, if you have multiple threads, one thread can enter the method, see that record is not present and it saves it, and at the same time another thread tries the same thing, you can end up in the situation where two threads try to save the same record, and you can get an exception.

To avoid the such race conditions, we can mark the method or a code block with a synchronized keyword.

How synchronized works?

Synchronized blocks or methods prevent thread interference. When one thread wants to access a method, it needs to acquire the lock on the monitoring object.

Once it gets it, no other thread can receive it until the current thread which holds the lock finishes with the execution of the synchronized method or block.

Then, other threads will wait until the lock can be acquired. In that way, the synchronized keyword assures that only one thread can execute the synchronized block at a time.

As we said, the synchronized keyword can be applied to methods and blocks.

Synchronized methods in Java

Both static and instance methods can be marked as synchronized.

When we make an instance method synchronized, only one thread per instance can execute the code inside it.

Declaring the synchronized instance method:

synchronized void method() {}

 

Synchronized method example

Let’s see what happens if two threads access the same non-synchronized method simultaneously:

public class SynchronizedInstanceMethodExample implements Runnable {

  public static void main(String[] args) {
    SynchronizedInstanceMethodExample runnable = new SynchronizedInstanceMethodExample();
    new Thread(runnable).start(); // creates one thread
    new Thread(runnable).start(); // creates second thread
  }

  // Inherited run method from the Runnable interface
  @Override
  public void run() {
    try {
      // Calling the non-synchronized method print()
      print();
    } catch (InterruptedException e) {
      System.out.println("Error occurred while running the print method using multiple threads...");
    }
  }

  // non-synchronized method
  void print() throws InterruptedException {

    System.out.println("Thread enters the method: " + Thread.currentThread().getName());
    Thread.sleep(2000);
    System.out.println("Thread finishes executing: " + Thread.currentThread().getName());

  }
}

We implemented the Runnable interface to execute the code using multiple threadsInside the print() method, we print what thread is currently executing the method and put some sleep to pause the current thread.

When we run the above program, we can see the following output:

Thread enters the method: Thread-1
Thread enters the method: Thread-2
Thread finishes executing: Thread-1
Thread finishes executing: Thread-2

You see that both methods entered the print() method. The Thread-2 didn’t wait for the Thread-1 to finish execution.

Now, let’s make the print() method synchronized and see the output:

  //synchronized method
  void print() throws InterruptedException {

    System.out.println("Thread enters the method: " + Thread.currentThread().getName());
    Thread.sleep(2000);
    System.out.println("Thread finishes executing: " + Thread.currentThread().getName());

  }
Output: Thread enters the method: Thread-1 Thread finishes executing: Thread-1 Thread enters the method: Thread-2 Thread finishes executing: Thread-2
 
Using the synchronized keyword, we ensure that Thread-2 enters the method when the Thread-1 finishes with the execution.
 
The same applies to the static methods.

Synchronized blocks in Java

We don’t need to synchronize a whole method if we don’t need to. We can just synchronize a code block inside it.

Example

  // non-synchronized method
  void print() throws InterruptedException {

    System.out.println("Thread enters the method: " + Thread.currentThread().getName());

    synchronized (this) { // synchronized code block
      System.out.println("Thread enters the code block: " + Thread.currentThread().getName());
      Thread.sleep(2000);
      System.out.println("Thread finishes executing the code block: " + Thread.currentThread().getName());
    }

    System.out.println("Thread finishes executing the method: " + Thread.currentThread().getName());

  }
Output: Thread enters the method: Thread-1 Thread enters the method: Thread-2 Thread enters the code block: Thread-1 Thread finishes executing the code block: Thread-1 Thread enters the code block: Thread-2 Thread finishes executing the method: Thread-1 Thread finishes executing the code block: Thread-2 Thread finishes executing the method: Thread-2
 
You see, here, both threads entered the non-synchronized method, but the Thread-2 needed to wait for the Thread-1 to finish executing the synchronized code block.
 
That would be all about using the synchronized keyword in Java. Proceed to the next lesson.

Happy coding!

Leave a Reply

Your email address will not be published. Required fields are marked *