As verticalarhat pointed out,
Java 1.5 and Java 1.6 have made concurrent programming a lot more accessible to developers. Java 1.5 introduced some concurrent collections and "Future Task" constructs. Java 1.6 has really improved and elaborated on all this, with Concurrent Queues, Thread Pools, Task Executors. Open-source frameworks such as http://ehcache.sf.net/ and springframework have evolved to fully-leverage them, one of my current favorites being org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor.
I've pushed to production a number of highly-loaded applications that use the living daylights out of those constructs, and it's a real joy to see all 8 of your CPU Cores equally-pegged as your app hums along.
Concurrent collections, queues and thread pools are a big deal. Until those were readily available and easy-to-use, many application-scaling patterns were only available if you spent a lot of money on high-priced frameworks from the likes of Oracle.