I use Netbeans Profiler:
alt text http://www.netbeans.org/images/v6/1/features/profiler-java-cut.png
Its free, has task based profiling, a heap walker, allows the insertion of profiling points, tracks memory usage and threading, but best of all it allows you to profile remote JVM's. You can even attach to ones which are already running.
Oh, and it works really well if you've a maven build for your project too.