栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 面试经验 > 面试问答

Java JVM中的指令重新排序

面试问答 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

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 hashpre_shared() {    if (hash == 0) { hash = 1; }    return hash;}public int hashpre_local() {    int h = hash;    if (h == 0) { hash = h = 1; }    return h;}

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

public int hashpre_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 r2public int hashpre_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上发生。


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

hashpre_shared

public int hashpre_shared() {    int h = hash;    if (hash != 0) return h;    return (hash = 1);}

该代码在单线程环境中严格等效(它将始终返回与原始方法相同的值),因此允许重新排序。但是,在多线程环境中,很明显,如果

hash
前两行之间的另一个线程将其从0更改为1,则此重新排序的方法将错误地返回0。



转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/573806.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号