gpt4 book ai didi

Java 同步未按预期工作

转载 作者:IT老高 更新时间:2023-10-28 20:50:11 25 4
gpt4 key购买 nike

我有一个“简单”的 4 类示例,它可靠地显示了多台机器上 java 同步的意外行为。正如您在下面看到的,鉴于 java sychronized 关键字的协定,Broke Synchronization 永远不应该从 TestBuffer 类中打印出来。

这里有 4 个类将重现该问题(至少对我而言)。我对如何修复这个损坏的示例不感兴趣,而是首先为什么会损坏

Sync Issue - Controller.java

Sync Issue - SyncTest.java

Sync Issue - TestBuffer.java

Sync Issue - Tuple3f.java

这是我运行它时得到的输出:

java -cp . SyncTest
Before Adding
Creating a TestBuffer
Before Remove
Broke Synchronization
1365192
Broke Synchronization
1365193
Broke Synchronization
1365194
Broke Synchronization
1365195
Broke Synchronization
1365196
Done

更新:@Gray 有迄今为止最简单的例子。他的例子可以在这里找到:Strange JRC Race Condition

根据我从其他人那里得到的反馈,看起来这个问题可能出现在 Windows 和 OSX 上的 Java 64 位 1.6.0_20-1.6.0_31(不确定更新的 1.6.0)上。没有人能够在 Java 7 上重现该问题。它可能还需要多核机器来重现该问题。

原始问题:

我有一个类提供以下方法:

  • remove - 从列表中删除给定的项目
  • getBuffer - 遍历列表中的所有项目

我已将问题简化为以下 2 个函数,它们都在同一个对象中,并且它们都是 同步的。除非我弄错了,否则永远不应该打印“中断同步”,因为在输入 remove 之前,应该始终将 insideGetBuffer 设置回 false。但是,在我的应用程序中,当我有 1 个线程重复调用 remove 而其他线程重复调用 getBuffer 时,它正在打印“中断同步”。症状是我得到一个 ConcurrentModificationException

另见:

Very strange race condition which looks like a JRE issue

Sun 错误报告:

这已被 Sun 确认为 Java 中的一个错误。它显然在 jdk7u4 中已修复(不知不觉?),但他们没有将修复程序向后移植到 jdk6。 Bug ID: 7176993

最佳答案

我认为您确实在查看 OSR 中的 JVM 错误。使用来自@Gray 的简化程序(稍作修改以打印错误消息)和一些选项来混淆/打印 JIT 编译,您可以看到 JIT 发生了什么。而且,您可以使用一些选项将其控制到可以抑制问题的程度,这为这是一个 JVM 错误提供了很多证据。

运行方式:

java -XX:+PrintCompilation -XX:CompileThreshold=10000 phil.StrangeRaceConditionTest

你会得到一个错误条件(像其他大约 80% 的运行一样)并且编译打印有点像:

 68   1       java.lang.String::hashCode (64 bytes)
97 2 sun.nio.cs.UTF_8$Decoder::decodeArrayLoop (553 bytes)
104 3 java.math.BigInteger::mulAdd (81 bytes)
106 4 java.math.BigInteger::multiplyToLen (219 bytes)
111 5 java.math.BigInteger::addOne (77 bytes)
113 6 java.math.BigInteger::squareToLen (172 bytes)
114 7 java.math.BigInteger::primitiveLeftShift (79 bytes)
116 1% java.math.BigInteger::multiplyToLen @ 138 (219 bytes)
121 8 java.math.BigInteger::montReduce (99 bytes)
126 9 sun.security.provider.SHA::implCompress (491 bytes)
138 10 java.lang.String::charAt (33 bytes)
139 11 java.util.ArrayList::ensureCapacity (58 bytes)
139 12 java.util.ArrayList::add (29 bytes)
139 2% phil.StrangeRaceConditionTest$Buffer::<init> @ 38 (62 bytes)
158 13 java.util.HashMap::indexFor (6 bytes)
159 14 java.util.HashMap::hash (23 bytes)
159 15 java.util.HashMap::get (79 bytes)
159 16 java.lang.Integer::valueOf (32 bytes)
168 17 s phil.StrangeRaceConditionTest::getBuffer (66 bytes)
168 18 s phil.StrangeRaceConditionTest::remove (10 bytes)
171 19 s phil.StrangeRaceConditionTest$Buffer::remove (34 bytes)
172 3% phil.StrangeRaceConditionTest::strangeRaceConditionTest @ 36 (76 bytes)
ERRORS //my little change
219 15 made not entrant java.util.HashMap::get (79 bytes)

共有三个 OSR 替换(编译 ID 上带有 % 注释的替换)。我的猜测是第三个,即调用 remove() 的循环,是造成错误的原因。这可以通过位于工作目录中的 .hotspot_compiler 文件从 JIT 中排除,其内容如下:

exclude phil/StrangeRaceConditionTest strangeRaceConditionTest

当你再次运行程序时,你会得到这个输出:

CompilerOracle: exclude phil/StrangeRaceConditionTest.strangeRaceConditionTest
73 1 java.lang.String::hashCode (64 bytes)
104 2 sun.nio.cs.UTF_8$Decoder::decodeArrayLoop (553 bytes)
110 3 java.math.BigInteger::mulAdd (81 bytes)
113 4 java.math.BigInteger::multiplyToLen (219 bytes)
118 5 java.math.BigInteger::addOne (77 bytes)
120 6 java.math.BigInteger::squareToLen (172 bytes)
121 7 java.math.BigInteger::primitiveLeftShift (79 bytes)
123 1% java.math.BigInteger::multiplyToLen @ 138 (219 bytes)
128 8 java.math.BigInteger::montReduce (99 bytes)
133 9 sun.security.provider.SHA::implCompress (491 bytes)
145 10 java.lang.String::charAt (33 bytes)
145 11 java.util.ArrayList::ensureCapacity (58 bytes)
146 12 java.util.ArrayList::add (29 bytes)
146 2% phil.StrangeRaceConditionTest$Buffer::<init> @ 38 (62 bytes)
165 13 java.util.HashMap::indexFor (6 bytes)
165 14 java.util.HashMap::hash (23 bytes)
165 15 java.util.HashMap::get (79 bytes)
166 16 java.lang.Integer::valueOf (32 bytes)
174 17 s phil.StrangeRaceConditionTest::getBuffer (66 bytes)
174 18 s phil.StrangeRaceConditionTest::remove (10 bytes)
### Excluding compile: phil.StrangeRaceConditionTest::strangeRaceConditionTest
177 19 s phil.StrangeRaceConditionTest$Buffer::remove (34 bytes)
324 15 made not entrant java.util.HashMap::get (79 bytes)

并且问题没有出现(至少在我所做的重复尝试中没有出现)。

此外,如果稍微更改 JVM 选项,可能会导致问题消失。使用以下任一方法都无法出现问题。

java -XX:+PrintCompilation -XX:CompileThreshold=100000 phil.StrangeRaceConditionTest
java -XX:+PrintCompilation -XX:FreqInlineSize=1 phil.StrangeRaceConditionTest

有趣的是,这两个的编译输出仍然显示了删除循环的 OSR。我的猜测(这是一个很大的猜测)是通过编译阈值延迟 JIT 或更改 FreqInlineSize 会导致 OSR 处理在这些情况下发生更改,从而绕过您可能遇到的错误。

here有关 JVM 选项的信息。

herehere有关 -XX:+PrintCompilation 的输出以及如何处理 JIT 所做的事情的信息。

关于Java 同步未按预期工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10982941/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com