我有以下课程:
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();
}
}
当我查看反汇编代码时,我看不出三种方法getNext()
,getNextSync()
和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
JMV如何区分这些方法?
生成的代码与这些方法以及它们的调用者相同。 JVM如何执行同步?
答案 0 :(得分:6)
应用于方法的synchronized
关键字只会在the JVM specification § 4.6 Methods中定义的方法定义上设置ACC_SYNCHRONIZED
标记。它在方法的实际字节码中不可见。
JLS § 8.4.3.6 synchronized Methods讨论了定义synchronized
方法和声明跨越整个方法体的synchronized
块的相似性(并使用相同的对象进行同步)的相似性:效果完全相同,但它们在.class
文件中的表示方式不同。
volatile
字段会产生类似的效果:它只是在字段(JVM § 4.5 Fields)上设置ACC_VOLATILE
标记。 访问字段的代码使用相同的字节码,但行为略有不同。
另请注意,此处仅使用 一个易失性字段非线程安全,因为易失性字段x++
上的x
为不是原子的!
答案 1 :(得分:4)
前两者的区别就在这里:
public int getNext();
bytecodes follow...
public synchronized int getNextSync();
bytecodes follow...
对于最后一个,volatile
是变量的属性,而不是方法或访问该变量的JVM字节码。如果您查看javap
输出的顶部,您会看到以下内容:
int last;
volatile int lastVolatile;
如果/当字节码由JIT编译器编译成机器代码时,我确信最终方法的结果机器代码会有所不同。