In the earlier post we learnt about the Java synchronized method. In this post, let’s learn about the synchronized block.
Video: To see the visual walk-through of this post, click below:
https://youtu.be/NIeEiK_eklE
What is Synchronized Block?
Synchronized block is used to prevent multiple threads from executing a portion of a code in a method at the same point in time. On the other hand, synchronized method will prevent multiple threads from executing the entire method at the same point in time.
Synchronized block example
In our earlier post, we explained the synchronized method through the ‘BoyFriend’ threads and ‘GirlFriend’ example program. Now, let’s rewrite the same example program using synchronized block approach.
Note: we haven’t made any changes on how we are launching the ‘BoyFriend’ threads. It remains as is. However, we have modified the ‘GirlFriend’ class to use synchronized block as shown below:01: public class SynchronizationBlockDemo { 02: 03: private static class BoyFriendThread extends Thread { 04: 05: @Override 06: public void run() { 07: 08: girlFriend.meet(); 09: } 10: } 11: 12: private static GirlFriend girlFriend = new GirlFriend(); 13: 14: public static void main(String[] args) { 15: 16: for (int counter = 0; counter < 10; ++counter) { 17: 18: BoyFriendThread fThread = new BoyFriendThread(); 19: fThread.setName("BoyFriend-" + counter); 20: fThread.start(); 21: } 22: } 23: }
If you notice, in the ‘GirlFriend’ class,we have introduced a new object the ‘assistant’ in line #3. Instead of making the entire ‘meet()’ method as synchronized, we have now introduced ‘synchronized (assistant) {‘ in line #7. This synchronized block ends on line #17 and it will prevent multiple threads executing these lines of code. Only one thread will be allowed to execute the code from line #8 to #17 at any given time. When we executed the above program below is the output we got:01: public class GirlFriend { 02: 03: private Object assistant = new Object(); 04: 05: public void meet() { 06: 07: synchronized (assistant) { 08: 09: try { 10: 11: String threadName = Thread.currentThread().getName(); 12: System.out.println(threadName + " meeting started!"); 13: Thread.sleep(100); 14: System.out.println(threadName + " meeting ended!!"); 15: } catch (Exception e) { 16: } 17: } 18: } 19: }
How do synchronized block work in Java?BoyFriend-0 meeting started! BoyFriend-0 meeting ended!! BoyFriend-9 meeting started! BoyFriend-9 meeting ended!! BoyFriend-8 meeting started! BoyFriend-8 meeting ended!! BoyFriend-7 meeting started! BoyFriend-7 meeting ended!! BoyFriend-6 meeting started! BoyFriend-6 meeting ended!! BoyFriend-5 meeting started! BoyFriend-5 meeting ended!! BoyFriend-4 meeting started! BoyFriend-4 meeting ended!! BoyFriend-3 meeting started! BoyFriend-3 meeting ended!! BoyFriend-2 meeting started! BoyFriend-2 meeting ended!! BoyFriend-1 meeting started! BoyFriend-1 meeting ended!!
JVM will allow only one thread to enter into a synchronized block code at a given point in time. When a thread enters a synchronized block, it acquires the lock of the object on which it’s synchronized. In the above example, it’s the ‘assistant’ object. Only after this thread releases the lock, other threads will be allowed to enter the synchronized block of the code. Say if the ‘BoyFriend-0’ thread is executing the synchronized block of the code, only after this thread exits the block, other threads will be allowed to enter the synchronized block of code. Until then, all other threads which are trying to invoke the synchronized block of code will be put to the BLOCKED thread state.
Threads behavior of a synchronized block
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 1: fastThread tool reporting 9 threads are in BLOCKED state
Fig 2: fastThread tool reporting 9 threads to be in BLOCKED state when accessing assistant Object
fastThread tool reports the total number of blocked threads and a transitive graph showing where they are BLOCKED. In this example (Fig 1), the tool reported that 9 threads are in BLOCKED state. From the transitive graph (Fig 2), you can notice that the ‘BoyFriend1’ is blocking the remaining 9 ‘BoyFriend’ threads. When clicking on the thread names, you can see its complete stack trace. Below is the stack trace of one of the ‘BoyFriend’ threads which is BLOCKED:
The above stack trace is very similar to the BLOCKED ‘BoyFriend’ thread stack trace in the synchronized method example. However, there is only one difference. In line #3, this ‘BoyFriend’ thread is waiting to acquire the lock of the ‘java.lang.Object’ (i.e. ‘assistant’), whereas in the synchronized method example, the BoyFriend thread was waiting to acquire the lock of the ‘GirlFriend’ object. Below is the stack trace of the BLOCKED ‘BoyFriend’ thread in the synchronized method example:01: java.lang.Thread.State: BLOCKED (on object monitor) 02: at learn.synchblock.GirlFriend.meet(GirlFriend.java:1 3) 03: - waiting to lock <0x00000007141e4330> (a java.lang.Object) 04: at learn.synchblock.SynchronizationBlockDemo$BoyFrien dThread.run(SynchronizationBlockDemo.java:10) 05: Locked ownable synchronizers: 06: - None
01: java.lang.Thread.State: BLOCKED (on object monitor) 02: at learn.synchornized.GirlFriend.meet(GirlFriend.java :7) 03: - waiting to lock <0x0000000714173850> (a learn.synchornized.GirlFriend) 04: at learn.synchornized.SynchronizationDemo$BoyFriendTh read.run(SynchronizationDemo.java:10) 05: Locked ownable synchronizers: 06: - None
Advantages of Synchronized block over Synchronized method
Synchronized block has following advantages when compared to the synchronized method:
a. Synchronize only portion of method
When you use a synchronized method, the entire code in that method will be synchronized. Say suppose if you want to synchronize only a portion of code in the method, you can’t use the synchronized method. In that circumstance, you need to use a synchronized block.
b. Synchronize on any object
When you use a synchronized method, you can’t use any other object other than the underlying object (in case of static synchronized method it would be the underlying class) of that method for synchronization. On the other hand, when you use a synchronized block, you can use any object. In the above example, we are using an ‘assistant’ object for synchronization (Which is totally different from the GirlFriend object in which this method was present).
c. Change Synchronizing objects based on certain conditions
You can change the objects on which you are synchronizing dynamically. Look at the below example:
Here, we are synchronizing the ‘myLock’ object. However, the ‘myLock’ can have different objects, based on the invoker of the ‘doSomething()’ method. Maybe, for each customer, we can pass different myLock objects. This is not achievable with synchronized methods.01: public void doSomething(Object myLock) { 02: 03: : 04: : 05: synchronize (myLock) { 06: 07: // code to be synchronized 08: } 09: : 10: : 11: }
Disadvantages of Synchronized Block over Synchronized Method
Synchronized block has following disadvantages, when compared to the synchronized method:
Clean code
Code readability is better with synchronized method over synchronized block. In the synchronized method scenario, it’s enough if you can just insert the ‘synchronized’ keyword in the method declaration, whereas in synchronized block you need to do several additional things. Below is the code of a synchronized method and synchronized block:
Fig: Synchronized method
Fig: Synchronized Block
You can notice that in the synchronized block, you need to do following additional steps:
1. Declare the synchronizing object
2. Write one extra line of code on the synchronizing object
3. Code to be synchronized needs to be given one more extra level of tab
4. Need to put one extra opening brace and closing brace
It clutters your code when compared to synchronized methods.
Safe Code
Synchronized methods might be more safe to write than synchronized block, for following two reasons:
a) NullPointerException
In a synchronized block, you synchronize the code block on a new object. At runtime, the synchronizing object can turn out to be null. In those circumstances, you will end up getting a NullPointerException.
b) Synchronizing on unsafe objects
There are certain objects which are risky to synchronize. Example: Strings & Boxed Objects (Integer, Float, Double,…). Because, these objects are deduplicated by the JVM at runtime for optimal performance. In such circumstances synchronized blocks will not work properly and it will lead to nasty bugs in your application.
Conclusion
In this post, we learnt about synchronized blocks in detail. If you would like to learn further on java synchronization and concurrency you may visit here.