Core Java

Can threads execute different synchronized methods on same object?

In our earlier post, we learnt that when a method is synchronized only one thread will be allowed to enter the method. In this post, let’s do a little bit of deep dive – What would happen if an object has two synchronized methods? When a thread is executing the first synchronized method, will another thread be allowed to execute the second synchronized method? 


Video: To see the visual walk-through of this post, click below:


Multiple synchronized methods in a same object example

 To facilitate our study, I have put-together an interesting program. In this program, we are trying to simulate two threads trying to execute two synchronized methods of the same object, at the same point in time.

01: public class GirlFriend {

02: 

03:    public void sing() {

04:       

05:       try {         

06:           for(int i = 1; i <= 10; ++i) {

07:                System.out.println("lullaby");

08:                Thread.sleep(100);

09:          }

10:       } catch (Exception e) {         

11:       }

12:    }

13:    

14:    public void count() {

15:       

16:       try {

17:           for(int i = 1; i <= 10; ++i) {

18:                System.out.println(i);

19:                Thread.sleep(100);

20:          }

21:       } catch (Exception e) {         

22:       }

23:    }   

24: }

 This program has a ‘GirlFriend’ class. It contains two synchronized methods: 

 1. ‘sing()’ declared in line #3 which prints ‘lullaby’ 10 times.

 2. ‘count()’ declared in line #14 which prints ‘1’ to ’10’.

 We have put the thread to sleep for 100 milliseconds after printing in line #8 and #19, so that we can capture thread dumps during the program execution, which is needed for our discussion.

01: public class SameObjectSynchDemo {

02: 

03:    private static GirlFriend girlFriend = new GirlFriend();

04:    

05:    private static class BoyFriend1 extends Thread {

06:       

07:       @Override

08:       public void run() {

09:          

10:          girlFriend.sing();

11:       }

12:    }

13:    

14:    private static class BoyFriend2 extends Thread {

15:       

16:       @Override

17:       public void run() {

18:          

19:          girlFriend.count();

20:       }

21:    }

22:    

23:    public static void main(String args[]) {

24:       

25:       new BoyFriend1().start();

26:       new BoyFriend2().start();

27:    }

28: }

This SameObjectSynchDemo class contains two threads:

a. ‘BoyFriend1’ thread which invokes ‘GirlFriend’ object’s ‘sing()’ method in line #10

b. ‘BoyFriend2’ thread which invokes ‘GirlFriend’ object’s ‘count()’ method in line #19

Both of these threads are launched concurrently in line #25, #26.

Synchronized methods execution output

 When we executed the above program, we got following as output:

lullaby

1

lullaby

2

lullaby

3

lullaby

4

lullaby

5

lullaby

6

lullaby

7

lullaby

8

lullaby

9

lullaby

10

Fig: Output when sing() and count() is not synchronized

You can see that the ‘GirlFriend’ object is singing and counting at the same time i.e. you can notice that ‘lullaby’ and numbers are mixed up and printed. If you are going to ask the ‘GirlFriend’ object to sing and count at the same time, it’s going to be quite confusing. We need to help her. This is where the synchronized method comes to help. 

Now, we made both ‘sing()’ and ‘count()’ as synchronized methods i.e., we introduced the ‘synchronized’ keyword in line #3 and line #14 of the ‘GirlFriend’ class. When we executed this modified program, we got following as output:

lullaby

lullaby

lullaby

lullaby

lullaby

lullaby

lullaby

lullaby

lullaby

lullaby

1

2

3

4

5

6

7

8

9

10

Fig: Output when sing() and count() is synchronized

You can clearly see the difference in the output. When both ‘sing()’ and ‘count()’ are synchronized, ‘GirlFriend’ object first completed her singing and then only started counting i.e. ‘lullaby’ was printed first and then ‘1’ to ’10’ was printed later. This should make the ‘GirlFriend’ object really happy. This magic is only happening because of synchronization. 

How do two Synchronized methods work in Java?

When a thread executes the synchronized method, it obtains the lock of the underlying object. Only one thread can hold the lock of an object at any given time. Since ‘BoyFriend1’ thread started first, when it entered the ‘sing()’ method, it acquired lock of the ‘GirlFriend’ object; when ‘BoyFriend2’ thread tries to enter the ‘count()’ method, it would try to acquire the lock of the same ‘GirlFriend’ object. Since ‘BoyFriend1’ thread is already holding on to the GirlFriend’s lock, ‘BoyFriend2’ thread will not be allowed to acquire the lock and it will be put to BLOCKED state. Only after the ‘BoyFriend1’ thread exits the ‘sing()’ method, it will release the GirlFriend’s lock. Only after that ‘BoyFriend2’ thread can enter the ‘count()’ method.

Threads behavior of Synchronized methods

To confirm this theory, we executed the above program and captured thread dump using open-source script yCrash. We analyzed the thread dump using the fastThread tool. Here is the generated thread dump analysis report of this simple program. Below is the excerpt from the thread dump analysis report:

Fig: fastThread tool reporting 1 thread is in BLOCKED state
Fig: Transitive graph showing ‘BoyFriend2’ blocked by ‘BoyFriend1’ (generated by fastThread)

Whenever threads are blocked, the fastThread tool will report them as a transitive graph. From the graph you can notice that ‘BoyFriend2’ is being blocked by ‘BoyFriend1’. (Note: This graph would make more sense especially when multiple threads are getting blocked. You can look at the introductory post where multiple threads got BLOCKED). When clicking on the thread names you can see its complete stack trace. Below are both threads stack trace:

BoyFriend1

Stack Trace is:

java.lang.Thread.State: TIMED_WAITING (sleeping)

at java.lang.Thread.sleep0(java.base@19.0.1/Native Method)

at java.lang.Thread.sleep(java.base@19.0.1/Thread.java:465)

at learn.synchornized.sameobject.GirlFriend.sing(GirlFriend.java:10)

- locked <0x00000007141e3fe0> (a learn.synchornized.sameobject.GirlFriend)

at learn.synchornized.sameobject.SameObjectSynchDemo$BoyFriend1.run(SameObjectSynchDemo.java:16)

Locked ownable synchronizers:

- None

Fig: BoyFriend1 thread stack trace showing it acquired the GirlFriend lock

BoyFriend2

Stack Trace is:

java.lang.Thread.State: BLOCKED (on object monitor)

at learn.synchornized.sameobject.GirlFriend.count(GirlFriend.java:19)

- waiting to lock <0x00000007141e3fe0> (a learn.synchornized.sameobject.GirlFriend)

at learn.synchornized.sameobject.SameObjectSynchDemo$BoyFriend2.run(SameObjectSynchDemo.java:25)

Locked ownable synchronizers:

- None

Fig: BoyFriend2 thread stack trace showing it got BLOCKED when trying to acquire the GirlFriend lock

You can notice that the ‘BoyFriend2’ thread is blocked, because it’s trying to acquire the lock ‘0x00000007141e3fe0’ (which is the object id of ‘GirlFriend’), when it’s trying to invoke the ‘count()’ method. On the other hand you can notice ‘BoyFriend1’ acquired the same lock ‘0x00000007141e3fe0’ and executed the ‘sing()’. ‘BoyFriend1’ wouldn’t release this lock until it completes executing the ‘sing()’ method. Thus the ‘BoyFriend2’ thread is stranded and put into BLOCKED state.

Conclusion

In this post, we learnt how JVM would behave when two threads try to execute different synchronized methods on the same object. You may also consider reading this post, where we attempt to explain how a JVM would behave when two threads try to execute the same synchronized method on different objects.

Published on Java Code Geeks with permission by Ram Lakshmanan, partner at our JCG program. See the original article here: Can threads execute different synchronized methods on same object?

Opinions expressed by Java Code Geeks contributors are their own.

Ram Lakshmanan

Ram Lakshmanan developed world's finest DevOps tools: GCeasy.io, fastThread.io, HeapHero.io. Every single day, millions & millions of people in North America—bank, travel, and commerce—use the applications that Ram Lakshmanan has architected. Ram is an acclaimed speaker in major conferences on scalability, availability, and performance topics. Recently, he has founded a startup, which specializes in troubleshooting performance problems.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Inline Feedbacks
View all comments
Back to top button