Java through the rabbit hole: synchronized method vs block
Lately I was wondering what’s the difference between synchronized method and block in Java. Assuming you’re using sync block monitor on this
they work exactly the same. So what’s the difference ? Let’s check what’s beneath the hood.
By the way all is executed and tested on Oracle jdk 1.8.0_101.
Simplest case
Let’s take the easiest example there is.
Both those methods will work the same and will be exclusively blocking. Is there any difference in generated bytecode ? Let’s check.
Internals
Bytecode generated from this simple case looks a little bit surprising. Well maybe not to all but definitely to some it will.
public synchronized void syncMethod();
Code:
0: return
public void syncBlock();
Code:
0: aload_0
1: dup
2: astore_1
3: monitorenter
4: aload_1
5: monitorexit
6: goto 14
9: astore_2
10: aload_1
11: monitorexit
12: aload_2
13: athrow
14: return
Exception table:
from to target type
4 6 9 any
9 12 9 any
Sync method looks like it does nothing at all. Sync block even generated exception throwing. So let’s now look at verbose bytcode.
public synchronized void syncMethod();
descriptor: ()V
flags: ACC_PUBLIC, ACC_SYNCHRONIZED
Code:
stack=0, locals=1, args_size=1
0: return
LineNumberTable:
line 28: 0
public void syncBlock();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=2, locals=3, args_size=1
0: aload_0
1: dup
2: astore_1
3: monitorenter
4: aload_1
5: monitorexit
6: goto 14
9: astore_2
10: aload_1
11: monitorexit
12: aload_2
13: athrow
14: return
Exception table:
from to target type
4 6 9 any
9 12 9 any
LineNumberTable:
line 31: 0
line 34: 4
line 35: 14
StackMapTable: number_of_entries = 2
frame_type = 255 /* full_frame */
offset_delta = 9
locals = [ class pl/spc/sync/Main, class java/lang/Object ]
stack = [ class java/lang/Throwable ]
frame_type = 250 /* chop */
offset_delta = 4
Now there’s at least additional method flag for sync method. Let’s see what JVM spec says about magical ACC_SYNCHRONIZED
flag.
For code written in the Java programming language, perhaps the most common form of synchronization is the synchronized method. A synchronized method is not normally implemented using monitorenter and monitorexit. Rather, it is simply distinguished in the run-time constant pool by the ACC_SYNCHRONIZED flag, which is checked by the method invocation instructions.
Simply it means that JIT compiler will handle syncing for us and it won’t use monitorenter
and monitorexit
opcodes.
Pros of such solution is that we don’t waste any method bytecodes for synchronization. But what about performance ?
Performance
Let’s change code a little bit so it won’t be empty
and write some simple test.
On average sync block is slower by 10-12%.
Summary
From what I tested I think that it’s better to use synchronized method instead of block if we want to synchronize on this
.