Java中不可预测的程序行为

时间:2010-03-02 18:48:15

标签: java random race-condition

我正用这个把头发拉出来,我想我会看到其他人的Java经验是否能够对这个问题有所了解。我编写了大量的程序代码,它本身就是一个更大的项目,所以我不能简单地发布它。但是,我将概述问题......

问题: 我的代码没有返回模拟的可预测结果。每次运行模拟时,都会记录各种统计数据。尽管代码相同(!),但执行结果之间的结果也不同。

我非常确定的事情不是问题(尽管如果你认为有“问题”请大声说出来):

  • 使用随机数生成器,但每次都以相同的值播种。
  • 该程序是单线程的,因此竞争条件不应成为问题。
  • 行为发生在调试模式,独立jar和IDE的正常执行中(我正在使用eclipse)。
  • 静态成员用于列表中的对象。使用for-each构造,但每次都应该以相同的顺序执行。
  • 在对刚才提到的列表进行排序的情况下,使用了Collections.sort(),因此应该是稳定的(同样,列表应该以相同的顺序排序)

任何人都可以想到我可能会忽略的东西吗?这一刻似乎深不可测! 谢谢!

6 个答案:

答案 0 :(得分:3)

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

答案 1 :(得分:3)

我假设您已在对象中覆盖 equals()hashCode()(或者您已编写自定义比较器)。如果您的对象中使用了随机数,那么不是排序中的条件,对吗?

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

答案 2 :(得分:2)

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

答案 3 :(得分:1)

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

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

答案 4 :(得分:0)

是否有垃圾收集的可能性?这可能会给你的时间增加一些随机性。如果您使用的是Sun JVM,则可以选择打印GC信息:

    -XX:-PrintGC               Print messages at garbage collection. Manageable.
    -XX:-PrintGCDetails        Print more details at garbage collection. Manageable.            
                               (Introduced in 1.4.0.)
    -XX:-PrintGCTimeStamps     Print timestamps at garbage collection. Manageable
                               (Introduced in 1.4.0.)

详细信息取自page

您还可以查看使用jstat获取有关正在进行的操作的性能统计信息。

答案 5 :(得分:0)

在不知道你的代码的情况下很难分辨,但这里有一些我要开始寻找的地方。

确保所有个人课程都按预期工作。这意味着,您至少应该unit test核心类。

将assert-Statements插入所有私有方法以进行其他检查,以确保传递给helper方法的数据有效。 (不要在公共方法中使用assert,在那里使用Exceptions)。

在所有关键点添加日志记录(级别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) 

为false,因为您比较了两个对象引用而不是值 还有,

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

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

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

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

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