繁体   English   中英

Java中不可预测的程序行为

[英]Unpredictable Program Behaviour in Java

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

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

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

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

谁能想到我可能会在这里俯瞰的东西? 这一刻似乎深不可测! 谢谢!

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

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

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

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

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

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

有没有垃圾收集的机会? 这可能会给你的时间增加一些随机性。 如果您使用的是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.)

从此页面获取的详细信息。

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

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

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

将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) 

是假的,因为你比较两个对象引用而不是值,

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

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

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

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM