Java synchronized Keyword, Synchronized Method and Block

Filed Under: Java

Java synchronized keyword is used in multithreading to create a code block that can be executed by only one thread at a time.


Why do we need Synchronization?

When we have multiple threads working on a shared entity, the end result might be corrupt. Let’s say we have a simple program to increase the counter variable of the object. This variable is shared across all the threads.


package com.journaldev.threads;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;

public class CounterThread implements Runnable {

	private int count;

	public int getCount() {
		return count;
	}

	public void setCount(int count) {
		this.count = count;
	}

	@Override
	public void run() {
		Random rand = new Random();
		try {
			Thread.sleep(rand.nextInt(1000));
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		count++;
	}

	public static void main(String[] args) throws InterruptedException {
		CounterThread ct = new CounterThread();

		List<Thread> threads = new ArrayList<>();
		for (int i = 0; i < 100; i++) {
			Thread t = new Thread(ct);
			threads.add(t);
			t.start();
		}
		// wait for every thread to finish
		for (Thread t : threads) {
			t.join();
		}

		System.out.println("Final Count = " + ct.getCount());
	}
}

We are using Thread join() method to make sure every thread is dead before we print the final count.

We are also using Random class to add some processing time in the run() method.

If you run the above program, you will notice that the final count varies almost every time.

Java Synchronization

The reason for this variance is the "count++" statement. It's not an atomic operation.

The count variable is read first, then 1 is added to it and then the value is assigned back to the count variable.

We have multiple threads working on the count variable at the same time. If a thread reads the count variable and before it can update it, another thread updates it. This will cause data corruption in our program.

Java provides the synchronized keyword to help in this scenario by marking the code to be executed by one thread only at any point in time.


Java synchronized Example

Let's fix the above program using the synchronized keyword. We can create a synchronized block around the "count++" operation.

The synchronized keyword requires an object argument that will be used to create the locking mechanism. We can create a dummy object in the class for this purpose.

Below is the updated code that will work fine and the final count will be 100. I have removed the common code so that the focus remains only on the synchronized keyword usage.


public class CounterThread implements Runnable {
...
	private final Object mutex = new Object();
...

	public void run() {
...
		synchronized (mutex) {
			count++;
		}
	}
...
}
Java synchronized Keyword Example

Java synchronized Keyword Example


How does synchronized keyword work internally?

Java synchronization logic is built around an internal entity called an intrinsic lock or monitor lock.

When a thread tries to enter a synchronized area, it has to first acquire the lock on the object. Then all the statements in the synchronized block are executed. Finally, the thread releases the lock on the object that can be acquired by other threads in the wait pool.

If the object is "null", the synchronized keyword will throw NullPointerException.


Java synchronized Block

When a block of code is wrapped around the synchronized keyword, it's called a synchronized block.

Syntax of synchronized block


synchronized (object) {
	// syhcnronized block code
}

Here is a simple example of a synchronized block in Java.


package com.journaldev.threads;

public class MyRunnable implements Runnable {

	private int counter;
	private final Object mutex = new Object();

	@Override
	public void run() {
		doSomething();
		synchronized (mutex) {
			counter++;
		}

	}

	private void doSomething() {
		// some heavy lifting work
	}

}

Java synchronized Method

Sometimes, every statement inside a method is required to be synchronized. In this case, we can synchronize the method itself.

Syntax of synchronized Method


access_modifiers synchronized return_type method_name(method_parameters) {
	method_code
}

Here is an example of java synchronized method.


package com.journaldev.threads;

public class MyRunnable implements Runnable {

	private int counter;

	@Override
	public void run() {
		increment(2);
	}

	private synchronized void increment(int i) {
		counter += i;
	}

}

Lock Object in Synchronized Method

Just like synchronized block, synchronized methods also require an object to lock.

  • If the method is static, the lock is acquired on the class.
  • If the method is non-static, the lock is acquired on the current object.

Java synchronized Method vs Block

  • Java synchronized method locks the current object, so if there is another synchronized method then the other threads will be waiting for the lock on the object even if there is no shared variable in these methods. Java synchronized block works on an object field, so it's better to use the synchronized block in this case.
  • If the object has multiple synchronized methods working on the same variables, then the synchronized method is preferred. For example, StringBuffer uses synchronized methods because of all the append() and insert() methods work on the same object.

Here is an example where we have multiple methods working on the same variable, so using the synchronized method is a better choice.


package com.journaldev.threads;

public class MyRunnable implements Runnable {

	private int counter;

	@Override
	public void run() {
		increment(2);
		decrement(1);
	}

	private synchronized void increment(int i) {
		counter += i;
	}

	private synchronized void decrement(int i) {
		counter -= i;
	}
}

Here is another example where the different methods are working on a different shared variable, so using a synchronized block is a better choice.


package com.journaldev.threads;

public class MyRunnable implements Runnable {

	private int positiveCounter;
	private int negativeCounter;

	private final Object positiveCounterMutex = new Object();
	private final Object negativeCounterMutex = new Object();

	@Override
	public void run() {
		increment(2);
		decrement(1);
	}

	private void increment(int i) {
		synchronized (positiveCounterMutex) {
			positiveCounter += i;
		}
	}

	private void decrement(int i) {
		synchronized (negativeCounterMutex) {
			negativeCounter -= i;
		}
	}
}

Conclusion

Java synchronized keyword is useful in avoiding data corruption in multithreaded programming. However, synchronization reduces the performance of the code because of the extra overhead of locking mechanism. Whether to use a synchronized block or synchronized method depends a lot on your project requirements.

Comments

  1. Debashis says:

    negetiveCounteramutex should be final or else because the reference to the non-final field may change anytime and then different threads might synchronize on different objects i.e. no synchronization at all.
    Advantages

    1. Debashis says:

      I think private would also meet the purpose. 😉

      1. Pankaj says:

        You have a valid point, making the mutex object final makes perfect sense. I have updated the article code.

Leave a Reply

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

close
Generic selectors
Exact matches only
Search in title
Search in content
Search in posts
Search in pages