Master java skills

Thread synchronization in java

Synchronization is the process of synchronizing the threads’ access to a shared resource. We know that threads run randomly depending on the thread scheduler implementation.

In certain situations, when multiple threads access a shared resource (object), then they work upon it simultaneously. This situation might result in a erroneous output. Let’s take an example of a file where multiple threads are working together on it. Some threads are reading from the file and some threads are writing into it. In such a situation, the reader threads might not read the expected value, since writer threads may not have finished before reader threads accessed it.

Java has solution for such scenarios. Synchronization is the solution. Thread synchronization means threads will access a resource/object in a synchronized (sequential) manner. Meaning, if one thread is accessing a resource, all other threads will wait. When the first thread will complete, another thread will get access to that resource, and the rest of the threads will wait.

In thread synchronization, only one thread gets access to a resource/object at any particular time. And until it completely finishes its task, no other thread is given access to that resource.

Types of synchronization

  1. Instance synchronization – In such cases, access to an instance/object is synchronized.
  2. Static synchronization – In such cases, access to static properties of a class is synchronized.

Lock or monitor

Every object in java has a lock associated with it. It is also known as monitor. Thread synchronization mechanism makes use of these locks. Whenever a thread wants access on an object, in a synchronized context, it needs to acquire the lock on that object. Once lock is acquired by that thread, no other thread can access that object. Once it is relased by the first thread, then only it can be acquired by other threads.

Thus using the lock, synchronized accessed to an object is ensured.

Example without synchronization

In the below example, we are going to run three threads without synchronizing the access to the object they work upon.

package com.javatrainingschool;

public class RunnableTask implements Runnable {

	public void run() {

		for (int i = 0; i < 5; i++) {
			System.out.println(Thread.currentThread().getName() + " : Value of i = " + i);
		}

	}

	public static void main(String[] args) {

		// Create a runnable task which all threads will share
		RunnableTask t = new RunnableTask();
		Thread t1 = new Thread(t);
		Thread t2 = new Thread(t);
		Thread t3 = new Thread(t);

		t1.start();
		t2.start();
		t3.start();

	}
}
Output :
Thread-0 : Value of i = 0
Thread-0 : Value of i = 1
Thread-0 : Value of i = 2
Thread-1 : Value of i = 0
Thread-2 : Value of i = 0
Thread-1 : Value of i = 1
Thread-0 : Value of i = 3
Thread-1 : Value of i = 2
Thread-2 : Value of i = 1
Thread-1 : Value of i = 3
Thread-0 : Value of i = 4
Thread-1 : Value of i = 4
Thread-2 : Value of i = 2
Thread-2 : Value of i = 3
Thread-2 : Value of i = 4

Above, we can see that the threads run randomly. Now, we will use synchronized keyword to synchronize the access of threads.

Synchronizing run() method

In the below example, we are going to synchronize run() method. But please note that, this synchronize will only work when multiple threads run the same object of runnable class.

package com.javatrainingschool;

public class RunnableTask implements Runnable {

	public synchronized void run() {

		for (int i = 0; i < 5; i++) {
			System.out.println(Thread.currentThread().getName() + " : Value of i = " + i);
		}

	}

	public static void main(String[] args) {

		// Create a runnable task which all threads will share
		RunnableTask rt = new RunnableTask();
		Thread t1 = new Thread(rt, "thread-a");
		Thread t2 = new Thread(rt, "thread-b");
		Thread t3 = new Thread(rt, "thread-c");

		t1.start();
		t2.start();
		t3.start();

	}
}
package com.javatrainingschool;

public class RunnableTask implements Runnable {

	public synchronized void run() {

		for (int i = 0; i < 5; i++) {
			System.out.println(Thread.currentThread().getName() + " : Value of i = " + i);
		}

	}

	public static void main(String[] args) {

		// Create a runnable task which all threads will share
		RunnableTask rt = new RunnableTask();
		Thread t1 = new Thread(rt, "thread-a");
		Thread t2 = new Thread(rt, "thread-b");
		Thread t3 = new Thread(rt, "thread-c");

		t1.start();
		t2.start();
		t3.start();

	}
}
Output :
thread-a : Value of i = 0
thread-a : Value of i = 1
thread-a : Value of i = 2
thread-a : Value of i = 3
thread-a : Value of i = 4
thread-c : Value of i = 0
thread-c : Value of i = 1
thread-c : Value of i = 2
thread-c : Value of i = 3
thread-c : Value of i = 4
thread-b : Value of i = 0
thread-b : Value of i = 1
thread-b : Value of i = 2
thread-b : Value of i = 3
thread-b : Value of i = 4

In the above output, it is clear that now a thread starts and finishes, then only another thread starts.

Note -> Synchronization in the above example will fail if the three threads run 3 different runnable tasks. We always have to keep in mind that synchronization happens when multiple threads wok on a single object.

Failed scenario :

package com.javatrainingschool;

public class RunnableTask implements Runnable {

	public synchronized void run() {

		for (int i = 0; i < 5; i++) {
			System.out.println(Thread.currentThread().getName() + " : Value of i = " + i);
		}

	}

	public static void main(String[] args) {

		// Create 3 runnable tasks which threads will run
		RunnableTask rt1 = new RunnableTask();
		RunnableTask rt2 = new RunnableTask();
		RunnableTask rt3 = new RunnableTask();
		Thread t1 = new Thread(rt1, "thread-a");
		Thread t2 = new Thread(rt2, "thread-b");
		Thread t3 = new Thread(rt3, "thread-c");

		t1.start();
		t2.start();
		t3.start();

	}
}
Output :
thread-a : Value of i = 0
thread-c : Value of i = 0
thread-b : Value of i = 0
thread-c : Value of i = 1
thread-a : Value of i = 1
thread-c : Value of i = 2
thread-b : Value of i = 1
thread-c : Value of i = 3
thread-a : Value of i = 2
thread-c : Value of i = 4
thread-b : Value of i = 2
thread-a : Value of i = 3
thread-b : Value of i = 3
thread-a : Value of i = 4
thread-b : Value of i = 4

In the above output, we can see that threads are not synchronized because they are running different tasks (working on different runnable objects).