What is Synchronization in Java?

Synchronization in Java

Synchronization in Java is that the capability to regulate the access of multiple threads to any shared resource.

Java Synchronization could be a higher possibility wherever we would like to permit only 1 thread to access the shared resource.

Why use Synchronization?

The synchronization is especially used to

  1. To prevent thread interference.
  2. To prevent consistency problems.

Types of Synchronization

There are two kinds of synchronization:

  1. Process Synchronization
  2. Thread Synchronization

Here, we are going to discuss solely thread synchronization.

Thread Synchronization

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

  1. Mutual Exclusive
    1. Synchronized method.
    2. Synchronized block.
    3. Static synchronization.
  2. Cooperation (Inter-thread communication in java)

Mutual Exclusive

Mutual Exclusive is one of a kind that helps maintains threads from interfering with each other while sharing data. It may be accomplished via the use of the following three ways:

  1. By Using Synchronized Method
  2. By Using Synchronized Block
  3. By Using Static Synchronization

Concept of Lock in Java

Synchronization is constructed around an internal entity referred to as the lock or monitor. Each object contains a lock-related to it. By convention, a thread that wants consistent access to an object's fields must acquire the object's lock before accessing them, then unleash the lock once it’s finished them.

From Java 5, the package java.util.concurrent.locks contains many lock implementations

Understanding the problem without Synchronization

Unsynchronized Code

Let's take a simple BankAccount class below. It holds state within the form of a balance, which might be increased and decreased using the credit and debit methods. Once employed in a single-threaded context, this object can behave as expected, crediting and debiting the amounts specified.

public class BankAccount {

 

  private double balance;

 

  public void credit(double amount){

    balance = balance + amount;

  }

 

  public void debit(double amount){

    balance = balance - amount;

  }

 

  public double getBalance(){

    return balance;

  }

}

However, when multiple threads call the credit and debit methods at the same time, we will find ourselves with unpredictable behavior and an incorrect balance. To visualize this in action, the test method below uses an  ExecutorService to submit a hundred account debits and a hundred account credits, every for £100.

@Test

public void testBankAccountWithoutSynchronization1(){

 

  BankAccount bankAccount = new BankAccount();

 

  ExecutorService executorService = Executors.newFixedThreadPool(10);

 

  IntStream.rangeClosed(1, 100).forEach(i->{

    executorService.submit(()-> {

      bankAccount.debit(100);

    });

 

    executorService.submit(()-> {

      bankAccount.credit(100);

    });

  });

 

  executorService.shutdown();

  System.out.println("Final Balance: " + bankAccount.getBalance());

}

After all debits and credits have run, we'd expect the account to own a balance of zero. However, what I concluded with was a balance of -100 as shown below. Note that if you are running the sample code, it’s going to take a variety of runs before you see a non-zero result.   

Final Balance: -100.0

So, What's the Problem?

The credit method takes the present balance, adds a nominative quantity to that, then assigns the new value back to balance. The problem is that adding a value to balance and then assigning that result back to balance isn’t an associate atomic operation. It means that it does not happen as one distinct unit of work. Instead, a thread could add the desired amount to the current balance, and before it has a chance to assign the new value back to balance, the balance variable is also updated by another thread. At this time, the balance value held by the primary thread is stale and therefore the resulting variable assignment is wrong.

public void credit(double amount){

    balance = balance + amount;      

}

To resolve the problem, we want to confirm that balance = balance + amount becomes an atomic operation, performed in isolation by one thread at a time.

Java Synchronized Method

The simplest way to accomplish this is by marking the method as synchronized. A synchronized the method uses an implicit lock to confirm that just one thread at a time will enter the method. As a result, any shared state referenced inside the method is not any longer vulnerable to being manipulated by multiple threads simultaneously. During this instance, the shared state we're protecting is the account balance.

public synchronized void credit(double amount){

    balance = balance + amount;        

}

Hope you found this article useful enough to gain some clarity over the concept of Synchronization of Multithreading in Java. If you wish to suggest to me some new facts and ideas about the topic or would like to correct me somewhere, feel free to leave a comment below. I’d love to know what you think!

Thanks for reading!!!

Related Articles: | Inter-thread Communication In Java

Comments