字节码指令和处理器操作之间的关系

2024-03-22

Java 规范保证原始变量赋值始终是原子的(除了long和双types.

相反,获取并添加 http://en.wikipedia.org/wiki/Fetch-and-add对应著名的操作i++增量操作将是非原子的,因为会导致读取-修改-写入操作。

假设这段代码:

public void assign(int b) {
    int a = b;
}

生成的字节码为:

public void assign(int);
    Code:
       0: iload_1       
       1: istore_2      
       2: return 

因此,我们看到作业由以下部分组成two步骤(加载和存储)。

假设这段代码:

public void assign(int b) {
        int i = b++;
}

字节码:

public void assign(int);
    Code:
       0: iload_1       
       1: iinc          1, 1    //extra step here regarding the previous sample
       4: istore_2      
       5: return 

知道 X86 处理器(至少是现代处理器)可以原子地执行增量操作,如下所示:

在计算机科学中,CPU 的取指令和加指令是一种特殊的指令。 以原子方式修改存储器内容的指令 地点。它用于实现互斥和并发 多处理器系统中的算法,信号量的推广。

因此,第一个问题:尽管字节码需要这两个步骤(加载和存储),但 Java 是否依赖这样一个事实:无论处理器的体系结构如何,赋值操作总是以原子方式执行,因此可以确保其规范中的永久原子性(对于原始赋值)?

第二个问题:确认使用非常现代的 X86 处理器并且不跨不同架构共享编译代码,根本不需要同步,这是错误的吗?i++操作(或AtomicInteger)?考虑到它已经是原子的了。


即使 i++ 将转换为 X86 Fetch-And-Add 指令也不会改变任何内容,因为 Fetch-And-Add 指令中提到的内存是指 CPU 的本地内存寄存器,而不是设备/应用程序的通用内存。在现代 CPU 上,此属性将扩展到 CPU 的本地内存缓存,甚至可以扩展到多核 CPU 的不同内核使用的各种缓存,但在多线程应用程序的情况下;绝对不能保证此分配将扩展到线程本身使用的内存的副本。

显然,在多线程应用程序中,如果一个变量可以被同时运行的不同线程修改,那么您必须使用系统提供的某种同步机制,并且不能依赖 i++ 指令占用单行 java代码是原子的。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

字节码指令和处理器操作之间的关系 的相关文章

随机推荐