相关疑难解决方法(0)

64位OpenJDK 7/8中并发长写的值完整性保证

注意:此问题与volatile,AtomicLong或所描述的用例中的任何感知缺陷无关.

我试图证明或排除的财产如下:

鉴于以下内容:

  • 最近的64位OpenJDK 7/8(最好7位,但8位也很有帮助)
  • 多处理英特尔基础系统
  • 非易失性长原始变量
  • 多个不同步的mutator线程
  • 一个不同步的观察者线程

观察者是否始终保证会遇到由变异线程写的完整值,或者是撕裂危险的单词?

JLS:不确定

此属性对于32位基元和64位对象引用是存在的,但是对于long和double,JLS不保证:

17.7.非原子对double和long的处理:
出于Java编程语言内存模型的目的,对非易失性long或double值的单次写入被视为两个单独的写入:每个32位一半写入一次.这可能导致线程从一次写入看到64位值的前32位,而从另一次写入看到第二次32位的情况.

但是抱着你的马:

[...]为了效率,这种行为是特定于实现的; Java虚拟机的实现可以自由地以原子方式或分两部分执行对long和double值的写入.鼓励Java虚拟机的实现避免在可能的情况下拆分64位值.[...]

因此,JLS 允许 JVM实现拆分64位写入,并鼓励开发人员相应地进行调整,但也鼓励 JVM实现者坚持使用64位写入.我们还没有回答最新版本的HotSpot.

HotSpot JIT:谨慎乐观

由于单词撕裂最有可能发生在紧密循环和其他热点的范围内,我试图分析JIT编译的实际汇编输出.长话短说:需要进一步测试,但我只能在long上看到原子64位操作.

我使用了hdis,一个OpenJDK的反汇编插件.在我老化的OpenJDK 7u25版本中构建并安装了插件之后,我开始编写一个简短的程序:

public class Counter {
  static long counter = 0;
  public static void main(String[] _) {
    for (long i = (long)1e12; i < (long)1e12 + 1e5; i++)
      put(i);
    System.out.println(counter);
  }

  static void put(long v) {
    counter += v;
  }
}
Run Code Online (Sandbox Code Playgroud)

我确保始终使用大于MAX_INT(1e12到1e12 + 1e5)的值,并重复操作足够的次数(1e5)以触发JIT.

编译后,我用hdis执行Counter.main(),如下所示:

java -XX:+UnlockDiagnosticVMOptions \ 
     -XX:PrintAssemblyOptions=intel \
     -XX:CompileCommand=print,Counter.put …
Run Code Online (Sandbox Code Playgroud)

java concurrency jvm jvm-hotspot java-memory-model

9
推荐指数
2
解决办法
628
查看次数

原子性在32/64位

问题是64位加载/存储操作何时被认为是原子操作.

  • 如果我有64位处理器,但我使用的是32位操作系统.我会有64位原子性吗?
  • 如果我使用64位操作系统但运行32位应用程序(使用WoW64),我会有64位原子性吗?

multithreading atomicity

5
推荐指数
1
解决办法
1215
查看次数