Thread Synchronization in Java

Introduction

When using two or more threads in a program, it may be happening that more than one thread wants to access a resource at the same time. For example, one thread might try to read data from a file while the other tries to change data in the same file. In such a case, the data may become inconsistent. The ideal situation would be to allow one thread to finish its task completely, and the other thread should be allowed to execute next. It must be ensured that a shared resource will be used by only one thread at a time. This is accomplished through a process known as synchronization.

Synchronization is based on the concept of the monitor. An object that serves as a mutually exclusive lock is called a monitor. Only one thread can own a monitor. A monitor can be considered similar to a small box that can hold only one thread at a time. If one thread enters the monitor, it means that the thread has acquired a lock, and all other threads must wait till that thread exits the monitor. If required, a thread that owns the monitor can re-enter the same monitor.

Synchronizing code

There is no class called Monitor in Java. Rather, each object has its own implicit monitor that is automatically entered when any of the object’s synchronized methods is called. For a thread to enter the monitor of an object. the programmer must invoke a method that has been created using the synchronized keyword. As long as a thread executes within a synchronized method, any other thread or synchronized method that tries to call it would have to wait. To exit the monitor and give up the control of the object to the next thread waiting, the owner of the monitor has to exit from the method. 

The example below demonstrates the working of a synchronized method.

class One {
    synchronized void display(int num) {
        System.out.print("" + num);
        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            System.out.println("Interrupted");
        }
        System.out.println(" Done");
    }
}

class Two implements Runnable {
    int number;
    One objOne;
    Thread objTh;

    public Two(One one_num, int num) {
        objOne = one_num;
        number = num;
        objTh = new Thread(this);
        objTh.start();
    }

    public void run() {
        objOne.display(number);
    }
}

class SynchMethod {
    public static void main(String args[]) {
        One objOne = new One();
        int digit = 10;
        Two objSynch1 = new Two(objOne, digit++);
        Two objSynch2 = new Two(objOne, digit++);
        Two objSynch3 = new Two(objOne, digit++);
        try {
            objSynch1.objTh.join();
            objSynch2.objTh.join();
            objSynch3.objTh.join();
        } catch (InterruptedException e) {
            System.out.println("Interrupted");
        }
    }
}

Output

Here the class has one method display() that takes a parameter of type int. This number is displayed with the suffix ‘done’. The Thread.sleep(1000) method is used to pause the current thread after the method display() is called.

The constructor of class Two takes a reference to an object objTh of class One and an integer variable. Here, a new thread is also created. This thread calls the run() method of the object objTh.

The main class SynchMethod instantiates the class One as objOne and creates three objects of the class Two. The same object objOne is passed to each of the objects of class Two. The method join() makes the caller thread wait till the calling thread terminates.

Summary

Synchronization is based on the concept of the monitor. One thread can own a monitor. For a thread to enter the monitor of an object. the programmer must invoke a method that has been created using the synchronized keyword.