I have the following class:
public class SeqGenerator {
int last = 0;
volatile int lastVolatile = 0;
public int getNext() {
return last++;
}
public synchronized int getNextSync() {
return last++;
}
public int getNextVolatile() {
return lastVolatile++;
}
public void caller() {
int i1 = getNext();
int i2 = getNextSync();
int i3 = getNextVolatile();
}
}
When I look at the disassembled code I don't see the difference between the representation of three methods getNext()
, getNextSync()
and getNextVolatile()
.
public int getNext();
Code:
0: aload_0
1: dup
2: getfield #2; //Field last:I
5: dup_x1
6: iconst_1
7: iadd
8: putfield #2; //Field last:I
11: ireturn
public synchronized int getNextSync();
Code:
0: aload_0
1: dup
2: getfield #2; //Field last:I
5: dup_x1
6: iconst_1
7: iadd
8: putfield #2; //Field last:I
11: ireturn
public int getNextVolatile();
Code:
0: aload_0
1: dup
2: getfield #3; //Field lastVolatile:I
5: dup_x1
6: iconst_1
7: iadd
8: putfield #3; //Field lastVolatile:I
11: ireturn
public void caller();
Code:
0: aload_0
1: invokevirtual #4; //Method getNext:()I
4: istore_1
5: aload_0
6: invokevirtual #5; //Method getNextSync:()I
9: istore_2
10: aload_0
11: invokevirtual #6; //Method getNextVolatile:()I
14: istore_3
15: return
How the JMV can distinguish between these methods?
The generated code is the same of these methods and also of their callers. How the JVM performs the synchronization?
The synchronized
keyword applied to a method just sets the ACC_SYNCHRONIZED
flag on that method definition, as defined in the JVM specification § 4.6 Methods. It won't be visible in the actual bytecode of the method.
The JLS § 8.4.3.6 synchronized Methods discusses the similarity of defining a synchronized
method and declaring a synchronized
block that spans the whole method body (and using the same object to synchronize on): the effect is exactly the same, but they are represented differently in the .class
file.
A similar effect happens with volatile
fields: It simply sets the ACC_VOLATILE
flag on the field (JVM § 4.5 Fields). The code that accesses the field uses the same bytecode, but acts slightly different.
Also please note that using only a volatile field here is not threadsafe, because x++
on a volatile field x
is not atomic!
The difference between the first two is right here:
public int getNext();
bytecodes follow...
public synchronized int getNextSync();
bytecodes follow...
As to the last one, volatile
is a property of the variable, not of the method or the JVM bytecodes that access that variable. If you look at the top of the javap
output, you'll see the following:
int last;
volatile int lastVolatile;
If/when the bytecodes are compiled into machine code by the JIT compiler, I am sure the resulting machine code will differ for the last method.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With