However often you find that its not enougth for you and then you will have to write some costume code yourself. You might think one message passing system is enougth but then its more and now you have to manage message from three subsystems in your application.
Ill use a langauge that makes things easy when things are easy and not very hard if they are hard.
Let's consider an example. One of the classic concurrency problems is managing a bank transfer. In this problem it's important that the debit and credit operations happen atomically. If one operation fails, then both operations should fail.
In Clojure, we'd write:
(defn transfer [from to amount]
(dosync
(alter from - amount)
(alter to + amount)))
How would you write the same thing in Java?A lot of the problems with dealing with concurrency are in communication between threads. BlockingQueues and Executors only deal with a small subset of concurrency problems, and blocked threads are a fairly inefficient use of resources compared to async solutions.
Why dont we ask Brian Goetz a Java Language Architect how "easy" it is, read his book [1] and then lets talk again how easy it is.
[1] http://www.amazon.com/Java-Concurrency-Practice-Brian-Goetz/...
For single-instance applications, sure. But for scalable systems, 90% of your concurrency is handled by whatever message broker you're using anyway. Tasks, Async processing, Blokcing Queues etc etc - they're all handled by your JMS provider.