开发者

Unpredictable Program Behaviour in Java

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 th开发者_如何转开发is 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!


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.


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.


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


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.


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.


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!

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜