4

I'm pulling my hair out with this and I thought I'd see if the greater Java experience of others might be able to shed some light on the problem. There is a large amount of program code I have written, which is itself within a larger project so I can't simply post it. However, I will outline the problem...

The issue: My code does not return predicatble results from a simulation. Each time the simulation is run, various statistics are recorded. Despite the fact that the code is identical (!), the results produced differ between executions.

Things I am pretty sure are not a problem (although if you think there's a "gotcha" please shout out):

  • A random number generator is used but it is seeded with the same value each time.
  • The program is single threaded so race conditions should not be an issue.
  • Behaviour occurs in both debug mode, standalone jar and normal execution from the IDE (I'm using eclipse).
  • Static members are used between objects in lists. The for-each construct is used, but this should execute in the same order each time.
  • In the case of sorting the lists just mentioned, Collections.sort() is utilised and so should be stable (again, lists should be ordered in the same order)

Can anyone think of something I might be overlooking here? This seems unfathomable at the moment! Thanks!

4

6 回答 6

3

您确定您正在使用您在所有地方创建的 Random 实例吗?请记住,对 Math.random() 的调用使用它们自己的 Random 实例。

于 2010-03-02T18:58:11.770 回答
3

我假设你已经覆盖 equals()你的对象和hashCode()你的对象(或者你已经编写了一个自定义比较器)。如果您的对象中使用了您的随机数,那么这不是排序的标准,对吗?

此外,如果您对这些项目进行排序,然后将它们放入 HashMap 或 HashSet - 这些结构不会保留您的顺序 - 请改用 TreeSet 或 TreeMap。

于 2010-03-02T18:58:16.547 回答
2

尝试在应用程序中添加大量跟踪,然后检查日志以查看其分歧之处。

于 2010-03-02T18:50:24.297 回答
1

您可以使用名为InTrace的工具来跟踪 Java 代码的执行。这将允许您比较程序不同运行之间的详细控制流。

注意:InTrace 是我编写的免费开源工具。

于 2011-06-19T19:52:42.917 回答
0

不知道你的代码很难说,但这里有一些我会开始寻找的地方。

确保您的所有个人课程都按预期工作。这意味着,您应该至少对核心类进行单元测试。

将 assert-Statements 插入所有私有方法以进行额外检查,以确保传递给辅助方法的数据有效。(不要将断言与公共方法一起使用,在那里使用异常)。

在所有关键点添加日志记录(级别 DEBUG,如果您使用的是 log4j 或类似的)或简单的 System.out.println() 语句,以获得值变化的想法。这将帮助您了解数据如何真正流经您的代码。

由于您使用的是 eclipse,因此请使用调试器并单步执行您的代码并注意意外的数据更改

检查错误的假设。例如,对于不是纯真/假检查的条件,else 块中的业务逻辑。例如,您经常在 GUI 中找到这样的代码

if (button == OK_BUTTON) {
    doOkButton();
} else {
    doCancelBotton(); // VERY dangerous. could be any Button
}

将此修复为

if (button == OK_BUTTON) {
    doOkButton();
} else if (button == CANCEL_BUTTON) {
    doCancelBotton();
} else {
    assert false : "Oops, a new button?"
}

您说您正在使用随机数生成器。你确定你每次都使用正确的并且它不会给你的输出增加随机性吗?你到底用它做什么?

你使用任何基于时间的东西吗?例如 System.currentTimeMillies?

您确定您使用的是正确的集合吗?并非所有元素都经过排序和排序,如果您尝试查看所有元素,则每次运行应用程序时可能会给出不同的结果。

验证您在集合中使用的所有类是否具有正确的 equals() 和 hashCode()

你在使用自动装箱吗?小心比较

 new Integer(5) == new Integer(5) 

是错误的,因为您比较两个对象引用而不是值,

Integer i = new Integer(5);
i++;

在 i++ 处创建一个新对象。这些可能很难发现,而且大多数情况下,如果您使用原语和集合,就会发生自动装箱。

您是否使用任何可能使您的假设无效(竞争条件等)的第三方库

使用FindBugs之类的工具对代码进行静态分析。它可能会给你一些提示。

那就是我要开始的地方。祝你好运!

于 2010-03-02T20:07:11.237 回答
0

有没有可能发生垃圾收集?这可能会为您的时间安排增加一点随机性。如果您使用的是 Sun JVM,则有一些选项可以打印出 GC 信息:

    -XX:-PrintGC 在垃圾回收时打印消息。可管理。
    -XX:-PrintGCDetails 在垃圾回收时打印更多细节。可管理。            
                               (在 1.4.0 中引入。)
    -XX:-PrintGCTimeStamps 在垃圾回收时打印时间戳。可管理
                               (在 1.4.0 中引入。)

取自此页面的详细信息。

您还可以查看使用jstat来获取有关正在发生的事情的一些性能统计信息。

于 2010-03-02T19:38:03.833 回答