Click here to Skip to main content
15,034,644 members
Articles / Programming Languages / Java
Article
Posted 13 Jun 2021

Tagged as

Stats

1.9K views
2 bookmarked

Threading in Java : Object Locks - I

Rate me:
Please Sign up or sign in to vote.
5.00/5 (2 votes)
13 Jun 2021CPOL4 min read
First in a series of articles to help readers with the concept of locks in Java
This series of articles makes an attempt to help readers with the concept of locks in Java. It is assumed that the reader has some prior knowledge of Java and threads creation in Java.

Introduction

Threading in Java is one of the most challenging topics to most of the developers exploring and using Java. There have been many books written on this topic, but incidentally these are written in very heavy technical language such that many entrants lose their interest after reading a few pages full of heavy technical jargon. This is an attempt to make things easy and understandable with Threading in Java. This series of articles makes an attempt to help with the concept of locks in Java.

Background

Let's explore the concept of Locks in Java. There is a typical question "Do you know object locks in Java? Do you know Class level locks in Java?" The articles to follow are going to demonstrate the concept of object locks and class level locks in Java.

Consider the following program:

Java
locks.java
==========

class processor implements Runnable{
    public void run(){
        display(); 
    }
    public void display(){
        for (int i = 0 ; i<= 5; i++) {
            System.out.println("i = " + i + " In thread" + Thread.currentThread());
        }
    }
} 

class locks {
    public static void main(String[] args)
    {
        processor p1 = new processor();
        Thread t1 = new Thread(p1, "t1");
        Thread t2 = new Thread(p1, "t2");
        t1.start();
        t2.start();
    }
}

The above program tries to create two threads with each thread trying to display numbers from 1 to 10. It has 2 classes, viz., "processor" and "locks".

The class "processor" implements Runnable interface as its primary job is to represent a thread that prints numbers 1 to 10 which it does by invoking the display method through the run method which represents the thread.

Within class "locks", we have the "main()" method. Within it, we create an object of processor class named "p1". Next, we create threads "t1" and "t2" based on the same object "p1". A point to remember is that both the threads here are based on the same object "p1" and that the "p1" is instantiated out of the class that implements Runnable to represent a Thread code to be executed.

The above program compiles and runs successfully to produce the following output:

C:\javaproj\locks>javac locks.java

C:\javaproj\locks>java locks
i = 0 In threadThread[t1,5,main]
i = 0 In threadThread[t2,5,main]
i = 1 In threadThread[t1,5,main]
i = 2 In threadThread[t1,5,main]
i = 1 In threadThread[t2,5,main]
i = 3 In threadThread[t1,5,main]
i = 2 In threadThread[t2,5,main]
i = 4 In threadThread[t1,5,main]
i = 3 In threadThread[t2,5,main]
i = 5 In threadThread[t1,5,main]
i = 4 In threadThread[t2,5,main]
i = 5 In threadThread[t2,5,main]

If you look closely at the output, it is an interleaved output. When i=0, thread "t1" prints the value of i in the forloop of display() function. The moment this is done, the time-slice is handled to thread "t2" which prints the value of i in the forloop of display() function. After this, "t2" is swapped out and "t1" is swapped into action. It increments the value of i to 1 and then prints the value of i in the forloop of display() function. The moment this is done, the time-slice is handled to thread "t2" which prints the value of i as 1 in the forloop of display() function. This moves on in an interleaved fashion till i reaches 5.

We need an orderly output such that first thread "t1" owns the for loop and prints all the values of "i" and then "t2" owns the for loop and prints all the values of "i". What comes to help is an object lock. Check the following program:

Java
class processor implements Runnable{
    public void run() {
        display(); 
    }
    public void display() {
        //===== Object Lock Used Here ======
        synchronized(this) {
            for (int i = 0 ; i<= 5; i++) {
                System.out.println("i = " + i + " In thread" + Thread.currentThread());
            }
        }
    }
} 

class locks {
    public static void main(String[] args) {
        processor p1 = new processor();
        Thread t1 = new Thread(p1, "t1");
        Thread t2 = new Thread(p1, "t2");
        t1.start();
        t2.start();
    }
}

Output
=======

i = 0 In threadThread[t1,5,main]
i = 1 In threadThread[t1,5,main]
i = 2 In threadThread[t1,5,main]
i = 3 In threadThread[t1,5,main]
i = 4 In threadThread[t1,5,main]
i = 5 In threadThread[t1,5,main]
i = 0 In threadThread[t2,5,main]
i = 1 In threadThread[t2,5,main]
i = 2 In threadThread[t2,5,main]
i = 3 In threadThread[t2,5,main]
i = 4 In threadThread[t2,5,main]
i = 5 In threadThread[t2,5,main]

The above program compliles and runs successfully to throw an Orderly Output as shown above. At first, "t1" executes the complete for loop in display(). Next, "t2" executes a complete for loop in display(). This happens because we are using the object lock. The for loop is wrapped in a block that uses an object lock. The keyword "this" refers to the current object which in our case is "p1". Both the threads "t1" and "t2" are created out of "p1" as shown below:

Java
Thread t1 = new Thread(p1, "t1");
Thread t2 = new Thread(p1, "t2");

Therefore when "t1" gets access to the for loop first, it locks the block with the object "this", i.e., "p1" and keeps the key inside its pocket. In the mean time, even if "t1" is swapped out, "t2" finds the doors closed as the key to object lock is carefully kept by "t1" in its pocket. "t1" executes the complete forloop and then only it unlocks the object lock for object p1 and leaves the key at the doorstep for anyone to use. The moment "t2" is swapped in, it picks up the key, enters the synchronized block and locks the block with the object "this", i.e., "p1" and keeps the key inside its pocket and proceeds for executing the for loop.

Thus "object lock" ensures that all the threads depending on the same object are synchronized.

Points of Interest

Thus "object lock" ensures that all the threads depending on the same object are synchronized.

History

  • 13th June, 2021: Initial version

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Chetan Kudalkar
Software Developer (Senior)
India India
I am a Software engineer with around 7+ years of experience. Most of my experience is in Storage technology.

Comments and Discussions

 
QuestionA question Pin
TX643013-Jun-21 12:09
MemberTX643013-Jun-21 12:09 
Hi Chetan, thank you for starting this topic as it might become an interesting read, but I will appreciate more information about Java version and the IDE to use, preferably I would like to suggest IntelliJ + Gradle, or VS Code, as there is no mention of these points in your article ....
Cheers,
Peter

AnswerRe: A question Pin
Chetan Kudalkar13-Jun-21 20:25
MemberChetan Kudalkar13-Jun-21 20:25 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.