Java 中不可预测的程序行为

发布于 2024-08-23 07:57:26 字数 533 浏览 4 评论 0原文

我对此感到非常烦恼,我想看看其他人的更丰富的 Java 经验是否能够阐明这个问题。我写了很多程序代码,这些代码本身就在一个更大的项目中,所以我不能简单地发布它。但是,我将概述问题......

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

我非常确定这不是问题(尽管如果您认为存在“陷阱”,请大声喊出来):

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

有人能想到我在这里可能会忽略的东西吗?这在目前看来是不可想象的! 谢谢!

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!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

清旖 2024-08-30 07:57:26

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

Are you sure that you are using the instance of Random that you created in all places? Remember that calls to Math.random() use their own instance of Random.

挽清梦 2024-08-30 07:57:26

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

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

I'm assuming you've overridden both equals() and hashCode() in your objects (or you've written a custom comparator). If your random number is used in your objects, it's not a criteria in the sort, right?

Also, if you're sorting these items then placing them into a HashMap or a HashSet - these structures will not preserve your order - use TreeSet or TreeMap instead.

平安喜乐 2024-08-30 07:57:26

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

try to add a lot of tracing into app and then examine logs to see where it diverges.

殊姿 2024-08-30 07:57:26

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

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

You could trace the execution of your Java code using a tool called InTrace. This would allow you to compare the detailed control flow between different runs of the program.

NOTE: InTrace is a free and open source tool which I have written.

南城旧梦 2024-08-30 07:57:26

有可能发生垃圾收集吗?这可能会给你的时间安排带来一点随机性。如果您使用的是 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获取一些有关正在发生的情况的性能统计数据。

Any chance of garbage collection occuring? That might add a little random-ness to your timing. If you're using a Sun JVM there are some options to print out GC information:

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

Details taken from this page.

You could also look at using jstat to get some performance statistics on what is going on.

江南月 2024-08-30 07:57:26

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

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

将断言语句插入所有私有方法以进行额外检查,以确保传递到辅助方法中的数据有效。 (不要将断言与公共方法一起使用,而应使用异常)。

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

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

检查是否有错误的假设。例如,else 块中的业务逻辑不是纯粹的真/假检查。例如,您经常在 GUI 中找到类似的代码

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

Fix this to

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

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

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

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

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

您是否使用自动装箱?小心比较

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

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

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

在 i++ 处创建一个新对象。这些可能很难发现,大多数时候,如果您使用基元和集合,就会发生自动装箱。

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

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

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

It is hard to tell without knowing your code, but here are some points where I'd start looking.

Make sure all your individual classes work as expected. This means, you should unit test at least your core classes.

Insert assert-Statements to all private methods for additional checking, to make sure data you pass into your helper methods is valid. (do NOT use assert with public methods, use Exceptions there).

Add logging (Level DEBUG, if you are using log4j or similar) or simple System.out.println() statements at all critical points to get an idea, where values change. This will help you understand how your data realy flows through your code.

Since you are using eclipse, use the debugger and step through your code and watch for unexpected data changes

Check for false assumptions. That is for example business logic in a else block for conditions that are not pure true/false checks. For example, you often find code like this in GUIs

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

Fix this to

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

You said you are using a Random Number Generator. Are you sure you are using the right one every time and it does not add randomness to your output? What exactly are you using it for?

Do you use anything time based? System.currentTimeMillies for example?

Are you sure you are using the right collection? Not all are sorted and ordered and could give different results each time the application runs if you try to look through all elements.

Verify that all classes you use in collections have proper equals() AND hashCode()

Are you using autoboxing? Be carefull with comparison

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

is false, because you compare two object references and not values
also,

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

creates a new object at i++. These can be hard to spot and most of the time, if you work with primitives and collections, autoboxing happens.

Are you using any third party library that could void your assumptions (race conditions etc)

Use a tool like FindBugs for a static analysis of your code. It might give you some hints.

That's where I'd start. Good Luck!

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文