Synchronization in Java

Introduction

Synchronization in Java is an important concept since Java is a multi-threaded language, It has the capability to control the access of multiple threads to any shared resource.

Synchronization in Java is possible by using Java keywords “synchronized”. It is a better option when requirement is only one thread to access the shared resource at a time.

The main advantage of synchronized keywords is we can resolve data inconsistency problems.

 

Why use Synchronization

The main advantage of synchronized keywords is we can resolve data inconsistency problems. To using Synchronization we can prevent thread interference.

The main limitation of a synchronized keyword is it increasing the waiting time of threads and affects the perforation of the system. Hence if there is no specific requirement it’s never recommended to use synchronized keyword.

 

Types of Synchronization

There are two types of synchronization

  1. Process Synchronization
  2. Thread Synchronization

 

Thread Synchronization:

Thread Synchronization is the capability to control the access of multiple threads to a shared resource, you need to ensure that the resource will be used by only one thread at a time.

Types of thread Synchronization:

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

  1. Mutual Exclusive
  2. Inter-thread communication

 

Mutual Exclusive is three types

  1. Synchronized method.
  2. Synchronized block.
  3. Static synchronization.

 

Concept of Lock in Java:

Every Object in java has a unique lock Synchronized concept, internally implemented by using this lock concept.

Whenever we are using Synchronized then only lock concept will come into the picture.

 

Synchronized method:

If a method declared as Synchronized then at a time only one thread is allowed to execute that method on the given object.

If a thread wants to execute any Synchronized method on any given object first it has to get lock of that object. Once the thread gets a lock then it is allowed to execute any Synchronized method on that object.

Once the Synchronized method completes than automatically the lock will be released.

While a thread executing any Synchronized method on the given object the reaming threads are not allowed to execute any Synchronized method on the given object simultaneously. But reaming thread is allowed to execute any Non-Synchronized methods simultaneously(lock concept is implemented based on the object but not based on method).

 

Let’s first see Example of without Synchronized method programming.

package com.technocalRound;

class Counting {
void printCounting(int n) {// No synchronized method
for (int i = 1; i <= 5; i++) {
System.out.println(n * i);
try {
Thread.sleep(400);
} catch (Exception e) {
System.out.println(e);
}
}

}
}

class MyThread1 extends Thread {
Counting c;

MyThread1(Counting c) {
this.c = c;
}

public void run() {
c.printCounting(5);
}

}

class MyThread2 extends Thread {
Counting c;

MyThread2(Counting c) {
this.c = c;
}

public void run() {
c.printCounting(100);
}
}

class TestSynchronization1 {
public static void main(String args[]) {
Counting obj = new Counting();// only one object
MyThread1 t1 = new MyThread1(obj);
MyThread2 t2 = new MyThread2(obj);
t1.start();
t2.start();
}
}

Output:

5
10
15
20
25
100
200
300
400

 

Example with Synchronized method programing.

package com.technocalRound;

class Counting {
synchronized void printCounting(int n) {// synchronized method
for (int i = 1; i <= 5; i++) {
System.out.println(n * i);
try {
Thread.sleep(400);
} catch (Exception e) {
System.out.println(e);
}
}

}
}

class MyThread1 extends Thread {
Counting c;

MyThread1(Counting c) {
this.c = c;
}

public void run() {
c.printCounting(5);
}

}

class MyThread2 extends Thread {
Counting c;

MyThread2(Counting c) {
this.c = c;
}

public void run() {
c.printCounting(100);
}
}

public class Example2 {
public static void main(String args[]) {
Counting obj = new Counting();// only one object
MyThread1 t1 = new MyThread1(obj);
MyThread2 t2 = new MyThread2(obj);
t1.start();
t2.start();
}
}

Output:

5
10
15
20
25
100
200
300
400

 

Synchronized block:

Synchronized block can be used to perform synchronization on very few lines of code of the method.

If very few lines of code required to Synchronization then it is never recommended to declare the entire method as Synchronized. We have to declare only those few lines of code inside the synchronized block.

If you put all the codes of the method in the synchronized block, it will work the same as the synchronized method.

The main advantage of a synchronized block over a synchronized method is, it reduces the waiting time of the thread and improves the performance of the system.

 

Example 1: We can declare a synchronized block to get the current object as follows.

synchronized (this)
{
---------
---------
---------
}

If the thread got lock of the current object, then only it will allow executing this bock.

 

Example 2: To get a lock of a particular object b and we can declare a synchronized block as follows

synchronized(b)
{
---------
---------
---------
}

If the thread got lock of the ‘b’ object, then only it will allow executing that bock.

 

Example 3: To get class level lock we can declare a synchronized block as follows

synchronized(className.class)
{
---------
---------
---------
}

If the thread got class level lock of className(Example) class then only it will be allowed to execute that bock.

Every object in java has a unique lock. But a thread can acquire more than one lock at a time( through different objects).

 

Example of Synchronized block:

package com.technocalRound;

class Counting {

void printCounting(int n) {
synchronized (this) {// synchronized block
for (int i = 1; i <= 5; i++) {
System.out.println(n * i);
try {
Thread.sleep(400);
} catch (Exception e) {
System.out.println(e);
}
}
}
}// end of the method
}

class MyThread1 extends Thread {
Counting c;

MyThread1(Counting c) {
this.c = c;
}

public void run() {
c.printCounting(5);
}

}

class MyThread2 extends Thread {
Counting c;

MyThread2(Counting c) {
this.c = c;
}

public void run() {
c.printCounting(100);
}
}

public class Example2 {
public static void main(String args[]) {
Counting obj = new Counting();// only one object
MyThread1 t1 = new MyThread1(obj);
MyThread2 t2 = new MyThread2(obj);
t1.start();
t2.start();
}
}

Output:

 5
10
15
20
25
100
200
300
400
500

 

ClassLavel Lock

Every class in Java has a unique lock. If the thread wants to execute a static Synchronized method than it is required class level lock.

While a thread executing a static Synchronized method then the remaining threads are not allowed to execute any static Synchronized method of that class simultaneity.

But the remaining thread is allowed to execute the following methods Simultaneously.

  1. Normal Static methods
  2. Normal instance methods
  3. Synchronized instance methods.

There is no link between object-level lock and class level lock both are independent of each other.

 

Static Synchronization

If you make any static method as synchronized, the lock will be in the class.

Example of Static Synchronization.

package com.technocalRound;

class Counting {

synchronized static void printCounting(int n) {
for (int i = 1; i <= 5; i++) {
System.out.println(n * i);
try {
Thread.sleep(400);
} catch (Exception e) {
}
}
}
}

class MyThread1 extends Thread {
public void run() {
Counting.printCounting(1);
}
}

class MyThread2 extends Thread {
public void run() {
Counting.printCounting(10);
}
}


public class Example2 {
public static void main(String t[]) {
MyThread1 t1 = new MyThread1();
MyThread2 t2 = new MyThread2();
t1.start();
t2.start();
}
}

Output:

1
2
3
4
5
10
20
30
40
50

 

Hope this was helpful for you. If you have any questions please feel free to leave a comment. Thank you for reading.

 

Leave a Reply

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