OK, maybe they have a few hassles. But compared to the various high-falutin' alternatives (co-routines, continuations, etc) they are reasonably easy to think about and reasonably easy to use.
I don't see that most of the alternatives get around the really fundamental problems anyhow - race conditions, lock-ordering, etc.
The hassles with java threads are primarily:
(1) objects should not have been synchronizable by default - there should have been an explicit "lock" primitive datatype.
That would have reduced object overhead and make locking a much more explicit thing, which can only be good, given how hard it is to get right.
(2) methods should not have been synchronizable - it effectively exposes part of the internal workings of the class in the interface.
The rest of the java threading model, especially with the 1.5 memory model and java.util.concurrent package, is actually pretty sane and easy to use.
When it comes to scaling programs to multi-core machines, projects like Fortress and X10 are on to a much better idea - libraries that make coding highly data parallel algorithms easily.
The fundamental problem with a lot of the so-called solutions is the same as the myth of distributed objects - that you can make the use of parallelism "invisible".
Unfortunately, this just isn't so - good parallelism coding requires that you do some intelligent partitioning of your code and data, and the very explicitness of threads makes those choices obvious.