java重排序_Java JVM中的指令重新排序

小编典典

在修改后的代码中:

public int hashCode() {

if (hash == 0) { // (1)

int off = offset;

char val[] = value;

int len = count;

int h = 0;

for (int i = 0; i < len; i++) {

h = 31*h + val[off++];

}

hash = h;

}

return hash; // (2)

}

(1)和(2)可以重新排序:(1)可以读取一个非null值,而(2)可以读取0。这在String类的实际实现中不会发生,因为计算是在局部变量上进行的返回值也是该局部变量,根据定义,该局部变量是线程安全的。

问题在于,如果在hash没有适当同步的情况下访问共享变量()时,Java内存模型不提供任何保证-

特别是它不能保证所有执行将顺序一致。如果hash是易失性的,则修改后的代码不会有问题。

ps:我相信该博客的作者是JLS第17章(Java内存模型)的作者之一-所以无论如何我都会相信他;-)

更新

在进行各种编辑/注释之后-让我们使用这两种方法更详细地查看字节码(为简单起见,我假设哈希码始终为1):

public int hashcode_shared() {

if (hash == 0) { hash = 1; }

return hash;

}

public int hashcode_local() {

int h = hash;

if (h == 0) { hash = h = 1; }

return h;

}

我的机器上的Java编译器生成以下字节码:

public int hashcode_shared();

0: aload_0 //read this

1: getfield #6 //read hash (r1)

4: ifne 12 //compare r1 with 0

7: aload_0 //read this

8: iconst_1 //constant 1

9: putfield #6 //put 1 into hash (w1)

12: aload_0 //read this

13: getfield #6 //read hash (r2)

16: ireturn //return r2

public int hashcode_local();

0: aload_0 //read this

1: getfield #6 //read hash (r1)

4: istore_1 //store r1 in local variable h

5: iload_1 //read h

6: ifne 16 //compare h with 0

9: aload_0 //read this

10: iconst_1 //constant 1

11: dup //constant again

12: istore_1 //store 1 into h

13: putfield #6 //store 1 into hash (w1)

16: iload_1 //read h

17: ireturn //return h

在第一个示例中,共有两次读取共享变量hash:r1和r2。如上所述,由于没有同步并且变量是共享的,因此将应用Java内存模型,并允许编译器/

JVM对这两个读取进行重新排序:可以在第1 *行之前插入第13行。

在第二个示例中,h由于对非共享变量的线程内语义和程序顺序保证,对局部变量的所有操作都需要顺序一致。

注意:与往常一样,允许重新排序的事实并不意味着将执行重新排序。实际上,在当前的x86

/热点组合中不太可能发生这种情况。但是它可能会在其他当前或将来的体系结构/ JVM上发生。

*这有点捷径,实际上可能发生的情况是编译器可能会这样重写hashcode_shared:

public int hashcode_shared() {

int h = hash;

if (hash != 0) return h;

return (hash = 1);

}

该代码在单线程环境中严格等效(它将始终返回与原始方法相同的值),因此允许重新排序。但是,在多线程环境中,很明显,如果hash前两行之间的另一个线程将其从0更改为1,则此重新排序的方法将错误地返回0。

2020-09-24

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值