This article tries to explain the meaning of keyword synchronized w.r.t. object as well as class level lock. The purpose of the exercise done in this article is to understand that a synchronized function internally uses an object level lock while a static synchronized function internally uses a class level lock for its entire code.
Introduction
Some wise men have said "Never judge people on their Face value. A lot is hidden in their subconscious mind". Does this hold true for synchronized functions? Let's see. Take the following program:
locks.java
-----------
class processor implements Runnable{
public void run() {
display();
}
public void display() {
synchronized (processor.lock){
for (int i = 0 ; i<= 5; i++) {
System.out.println("i = " + i + " In thread2" + Thread.currentThread() );
}
}
}
}
class locks {
public static void main(String[] args) {
processor p1 = new processor();
processor p2 = new processor();
Thread t1 = new Thread(p1, "t1");
Thread t2 = new Thread(p2, "t2");
t1.start();
t2.start();
}
}
Output
=======
i = 0 In thread2Thread[t1,5,main]
i = 1 In thread2Thread[t1,5,main]
i = 2 In thread2Thread[t1,5,main]
i = 3 In thread2Thread[t1,5,main]
i = 4 In thread2Thread[t1,5,main]
i = 5 In thread2Thread[t1,5,main]
i = 0 In thread2Thread[t2,5,main]
i = 1 In thread2Thread[t2,5,main]
i = 2 In thread2Thread[t2,5,main]
i = 3 In thread2Thread[t2,5,main]
i = 4 In thread2Thread[t2,5,main]
i = 5 In thread2Thread[t2,5,main]
The above program compiles and runs successfully to produce a desired synchronized output. This needs no explanation. The threads t1
and t2
are synchronized using a Class level lock "processor.lock
" such that the for
loop in the display()
function is executed by one and only one thread created out of any object of the processor class.
Now take the similar program with a slightly different look.
locks.java
----------
class processor implements Runnable{
public void run() {
display();
}
public static synchronized void display() {
for (int i = 0 ; i<= 5; i++) {
System.out.println("i = " + i + " In thread2" + Thread.currentThread() );
}
}
}
class locks {
public static void main(String[] args) {
processor p1 = new processor();
processor p2 = new processor();
Thread t1 = new Thread(p1, "t1");
Thread t2 = new Thread(p2, "t2");
t1.start();
t2.start();
}
}
Output
=======
i = 0 In thread2Thread[t1,5,main]
i = 1 In thread2Thread[t1,5,main]
i = 2 In thread2Thread[t1,5,main]
i = 3 In thread2Thread[t1,5,main]
i = 4 In thread2Thread[t1,5,main]
i = 5 In thread2Thread[t1,5,main]
i = 0 In thread2Thread[t2,5,main]
i = 1 In thread2Thread[t2,5,main]
i = 2 In thread2Thread[t2,5,main]
i = 3 In thread2Thread[t2,5,main]
i = 4 In thread2Thread[t2,5,main]
i = 5 In thread2Thread[t2,5,main]
The above program compiles and runs successfully to produce a desired output exactly similar to the earlier program. Well, the only change here is that we have declared display as a static synchronized function(). We get a similar output exactly like the earlier program.
public static synchronized void display() {
....
....
....
}
EXACTLY EQUALS
public void display() {
synchronized(process.lock) {
....
....
....
....
}
}
And NOT EQUAL TO
public void display() {
......
......
......
synchronized(process.lock){
....
....
....
}
}
Thus when you see a function declared as static
synchronized, it means the code within it is guarded by a class level lock.
Now let's move on to object
locks. Take the following program:
locks.java
-----------
class processor implements Runnable{
public void run() {
display();
}
public void display() {
synchronized (this){
for (int i = 0 ; i<= 5; i++) {
System.out.println("i = " + i + " In thread2" + Thread.currentThread() );
}
}
}
}
class locks {
public static void main(String[] args) {
processor p1 = new processor();
processor p2 = new processor();
Thread t1 = new Thread(p1, "t1");
Thread t2 = new Thread(p1, "t2");
t1.start();
t2.start();
}
}
Output
=======
i = 0 In thread2Thread[t1,5,main]
i = 1 In thread2Thread[t1,5,main]
i = 2 In thread2Thread[t1,5,main]
i = 3 In thread2Thread[t1,5,main]
i = 4 In thread2Thread[t1,5,main]
i = 5 In thread2Thread[t1,5,main]
i = 0 In thread2Thread[t2,5,main]
i = 1 In thread2Thread[t2,5,main]
i = 2 In thread2Thread[t2,5,main]
i = 3 In thread2Thread[t2,5,main]
i = 4 In thread2Thread[t2,5,main]
i = 5 In thread2Thread[t2,5,main]
The above program compiles and runs successfully to produce a desired synchronized output. This needs no explanation. The threads t1
and t2
are synchronized using an object level lock "this
" such that the for
loop in the display()
function is executed by one and only one thread created out of one and only one object of the processor class.
Now take the similar program with a slightly different look.
locks.java
----------
class processor implements Runnable{
public void run() {
display();
}
public synchronized void display() {
for (int i = 0 ; i<= 5; i++) {
System.out.println("i = " + i + " In thread2" + Thread.currentThread() );
}
}
}
class locks {
public static void main(String[] args) {
processor p1 = new processor();
processor p2 = new processor();
Thread t1 = new Thread(p1, "t1");
Thread t2 = new Thread(p1, "t2");
t1.start();
t2.start();
}
}
Output
=======
i = 0 In thread2Thread[t1,5,main]
i = 1 In thread2Thread[t1,5,main]
i = 2 In thread2Thread[t1,5,main]
i = 3 In thread2Thread[t1,5,main]
i = 4 In thread2Thread[t1,5,main]
i = 5 In thread2Thread[t1,5,main]
i = 0 In thread2Thread[t2,5,main]
i = 1 In thread2Thread[t2,5,main]
i = 2 In thread2Thread[t2,5,main]
i = 3 In thread2Thread[t2,5,main]
i = 4 In thread2Thread[t2,5,main]
i = 5 In thread2Thread[t2,5,main]
The above program compiles and runs successfully to produce a desired output exactly similar to the earlier program. Well, the only change here is that we have declared display as a synchronized function(). We get a similar output exactly like the earlier program.
public synchronized void display() {
....
....
....
}
EXACTLY EQUALS
public void display() {
synchronized(this) {
....
....
....
....
}
}
And NOT EQUAL TO
public void display() {
......
......
......
synchronized(this){
....
....
....
}
}
Thus when you see a function declared as synchronized, it means the code within it is guarded by a object level lock.
The purpose of this exercise was to understand that a synchronized function internally uses an object level lock while a static synchronized function internally uses a class level lock for its entire code. Well, indeed a lot is hidden behind the subconscious mind of the keyword synchronized in Java. What say?
Points of Interest
Static synchronized when applied to a method refers to class level lock while mere synchronized when applied to a method refers to object level lock.
Readers, please feel free to leave a comment whether you feel this article was helpful for you. This makes me understand if i need to add some more things as a part of explaination. Your feedback is most welcome. Thanks!
History
- 19th June, 2021: Initial revision