If you want to have a good laugh: Node JS and Server side Java Script. Here, someone from the Java camp complains that Node.JS really isn't to be taken seriously and then produces the best example why something like Node.JS (and many other alternatives for server programming) exists - because the Java code gets longer and longer with each step. And even after several iterations for an example that is quite simple to implement in Node.JS (or e.g. with gevent in Python), a few errors and gaps in the Java code are already mentioned in the first comments.

Don't get me wrong - Java has a lot of good solutions for programming with multiple threads in the standard library. Probably the largest selection of possibilities for programming with multiple threads of all currently available languages. But as so often in life: threads are not the answer to all questions of parallelization. Especially when it comes to high request load, the assessment in the comments that 20K threads are already very high is ridiculous - tell that to the programmers of Eve Online, where every ship in their virtual universe is modeled as a microthread.

Java is an interesting platform, precisely because it comes with many low-level libraries with which you can do very interesting things - and which are helpful to build reasonable high-level constructs on top of them. For example, in combination with languages like Clojure or Scala, the thread monster loses some of its terror. But sometimes the answer is not the thread, but asynchronous IO (both for disk access and network access) and the intensive use of coroutines or continuations.

Also, the incomprehension of Java programmers about the approach of solving the multi-core problem simply with several parallel processes and message-passing between them is quite strange in 2011 - after all, 2009 and 2010 were the revival years for Erlang (don't forget, the language has existed for much longer) and the central idea of Erlang is precisely to set network- and CPU-spanning message-passing as the standard in order to achieve very simple parallelizability and scalability.

Java programmers always remind me of the COBOL programmers of my early days, who in every language and every programming approach deliberately picked out the things that were solved differently in COBOL (and sometimes even perhaps a bit simpler) - but then fell flat on their faces when they had to solve real problems outside the COBOL comfort zone with them.

The best thing about Java is the JVM and thus a platform that makes the multi-paradigm and multi-language approaches possible with which you can then use the tools for problems that are appropriate for them. And even then, sometimes the answer is still Node.JS or another small, lean, asynchronous server. Because even with a large collection of various hammers, you will still get a screwdriver for the screw.