1 回答
TA贡献1829条经验 获得超6个赞
通过查看为类似情况生成的字节码,我们可以看到锁定字段的对象地址被复制并用于获取和释放锁。所以原始锁定对象用于锁定。
在同步块内用新对象更改锁定字段后,另一个线程可以获取新对象的锁定,并可以进入同步代码块。像这样使用同步,不提供线程之间的同步。您应该使用另一个对象进行锁定。(如最终对象 cacheLock = new Object())
仅供参考,这种用法不会阻止垃圾收集。由于这里提到的对象地址在该方法的栈帧内,一旦方法执行完毕,栈帧将被销毁,不再保留对旧对象的引用。(但不要像这样使用同步。)
您可以在此处查看 JVM 指令集
public class SyncTest {
private Long value;
public static void main(String[] args) {
new SyncTest().testLock();
}
public SyncTest() {
value = new Long(1);
}
private void testLock() {
synchronized (this.value) {
this.value = new Long(15);
}
}
}
private void testLock();
0 aload_0 [this]
1 getfield t1.SyncTest.value : java.lang.Long [27] // push value field to operand stack
4 dup // duplicate value field push it to operand stack
5 astore_1 // store the top of the operand stack at [1] of local variable array (which is the duplicated value field)
6 monitorenter // aquire lock on top of the operand stack
7 aload_0 [this]
8 new java.lang.Long [22]
11 dup
12 ldc2_w <Long 15> [31]
15 invokespecial java.lang.Long(long) [24]
18 putfield t1.SyncTest.value : java.lang.Long [27]
21 aload_1 // load the [1] of local variable array to the operand stack (which is the duplicated value field previously stored)
22 monitorexit // release the lock on top of the operand stack
23 goto 29
26 aload_1
27 monitorexit
.....
添加回答
举报
