long start = System.currentTimeMillis();
... do something ...
long end = System.currentTimeMillis();
System.out.println("Did something, took "+(end-start)/1000.0+"s");
Although this involves code changes and recompilation, this method is very
flexible. It provides accurate absolute times for how long a section of code
takes, and is the only technique that can be used to analyse where time is spent
within a method.
This has the advantage that no code changes are needed, and it's free! It also works with any JVM and platform, not just those supported by tool vendors. The main disadvantage is that only the immediate caller of a method is logged, so all invocations of a method tend to be rolled into one, irrespective of where in your code it's used, which makes it very difficult to analyse particular situations.
These use the low level JVM debugger API to monitor what the virtual machine is doing. OptimizeIt has two modes, sampling mode (where it lets the application run but periodically samples which method it's in) and instrumentation mode (where it traps each call as it happens). These provide much more detail on a particular execution path through your code, overcoming the deficiencies of built in profiling. However, sometimes the sheer volume of data produced is overwhelming and a simpler approach is all that's required.
The Hotspot (JDK 1.3) VM has several other profiling options, eg. to provide statistics on how well the compiler is performing, but I haven't looked into these in detail yet. Type "java -X" or "java -Xrunhprof:help" for details.
Why is so much time spent in Object.wait()? This is where a thread spends all its time when it's waiting for another thread to finish or for I/O to complete, including waiting for the user to press a key or move the mouse, so it's almost always guaranteed to be the method at the top of the list. In general, you won't get any very meaningful results from analysing the wait() method and should start instead by analysing a method you know is significant in your code.