Synchronization blocks and methods in java - Walking Techie

Blog about Java programming, Design Pattern, and Data Structure.

Saturday, August 20, 2016

Synchronization blocks and methods in java

What is synchronization?

When two or more threads access the same share resource, need some way to ensure that the resource is using by only one thread at a time. This process by which this is achieved is called synchronization.

Key to synchronization is the concept of the monitor. A monitor is an object that is used as a mutually exclusive lock. Only one thread can own the monitor at a given time. When a thread acquires a lock, it is said to have entered monitor. All other threads attempting to enter the locked monitor will be suspended until the first thread exits from the monitor. These threads called as waiting threads.

Thread can acquire lock in two ways:

  1. Using synchronized method
  2. Using synchronized block

All objects have their own implicit monitor associated with them.

Using synchronized method

Lets acquire the lock by entering the synchronized method. Once one thread enter any synchronized method on instance, no other threads can enter any other synchronized methods on the same instance. However, non-synchronized methods on that instance will continue to be callable.

Example: We have created the MyRunnable class and created its object. We have created two thread of same runnable target. Then we have started the thread and calling the synchronized display method from run() method. Once thread enter into synchronized display method, it acquired object lock on instance of MyRunnable class. Thread will leave lock when it exits from synchronized method.

Lets we understand above explanation with a program.

public class MyRunnable implements Runnable {

 @Override
 public void run() {
  display();
 }

 public synchronized void display() {
  System.out.println(Thread.currentThread().getName()
    + " is acquired object lock.");
  for (int i = 1; i <= 5; i++) {
   System.out.println(Thread.currentThread().getName()
     + " is executing. Value of i=" + i);
   try {
    Thread.sleep(1000);
   } catch (InterruptedException e) {
    e.printStackTrace();
   }
  }
  System.out.println(Thread.currentThread().getName() + " is completed.");
 }
}
MethodSynchronizationDemo
public class MethodSynchronizationDemo {

 public static void main(String[] args) {
  // create an runnable target object
  MyRunnable myRunnable = new MyRunnable();
  Thread t1 = new Thread(myRunnable);
  Thread t2 = new Thread(myRunnable);
  t1.start();
  t2.start();
 }
}

Output of the above program

Thread-0 is acquired object lock.
Thread-0 is executing. Value of i=1
Thread-0 is executing. Value of i=2
Thread-0 is executing. Value of i=3
Thread-0 is executing. Value of i=4
Thread-0 is executing. Value of i=5
Thread-0 is completed.
Thread-1 is acquired object lock.
Thread-1 is executing. Value of i=1
Thread-1 is executing. Value of i=2
Thread-1 is executing. Value of i=3
Thread-1 is executing. Value of i=4
Thread-1 is executing. Value of i=5
Thread-1 is completed.

If we notice above output, Thread-0 entered the synchronized method and acquired myRunnable's lock. Meanwhile Thread-1 is keep waiting for myRunnable's lock. Once Thread-0 completed. Thread-1 acquired lock on monitor and start executing.

Using synchronized block

Creating synchronized methods within classes are easy and effective way of achieving synchronization. It will not work in all cases. Why?, consider a scenario where you want to synchronize access to objects of a class that was not designed for multi-threaded access. That is, the class does not use synchronized methods. Further, this class is not created by you, but a third party, and you do not have access to the source code. So in this situation, you can simply put the calls to method of this class inside synchronized block.

Syntax of synchronized block:

synchronized(objRef) {
// statements to be synchronized
}

Now see the example of synchronized block.

public class MyRunnable implements Runnable {

 @Override
 public void run() {
  synchronized (this) {
   display();
  }
 }

 public void display() {
  System.out.println(Thread.currentThread().getName()
    + " is acquired object lock.");
  for (int i = 1; i <= 5; i++) {
   System.out.println(Thread.currentThread().getName()
     + " is executing. Value of i=" + i);
   try {
    Thread.sleep(1000);
   } catch (InterruptedException e) {
    e.printStackTrace();
   }
  }
  System.out.println(Thread.currentThread().getName() + " is completed.");
 }
}
SynchronizedBlockDemo.java
public class SynchronizedBlockDemo {

 public static void main(String[] args) {
  // create an runnable target object
  MyRunnable myRunnable = new MyRunnable();
  Thread t1 = new Thread(myRunnable);
  Thread t2 = new Thread(myRunnable);
  t1.start();
  t2.start();
 }
}

Output of the above program

Thread-0 is acquired object lock.
Thread-0 is executing. Value of i=1
Thread-0 is executing. Value of i=2
Thread-0 is executing. Value of i=3
Thread-0 is executing. Value of i=4
Thread-0 is executing. Value of i=5
Thread-0 is completed.
Thread-1 is acquired object lock.
Thread-1 is executing. Value of i=1
Thread-1 is executing. Value of i=2
Thread-1 is executing. Value of i=3
Thread-1 is executing. Value of i=4
Thread-1 is executing. Value of i=5
Thread-1 is completed.

If we notice above output, Thread-0 entered the synchronized block and acquired myRunnable's lock. Meanwhile Thread-1 is keep waiting for myRunnable's lock. Once Thread-0 completed. Thread-1 acquired lock on monitor and start executing.

No comments :

Post a Comment