Fine-grained synchronization to serve a file
Java's low level thread synchronization mechanism (synchronized blocks, volatile variables, wait(), notify(), etc) were proven to be tricky for the human single threaded mindset. Threading hazards like deadlock, thread starvation, and race conditions, which result from incorrect use of low level thread synchronization, are also hard to detect and debug.

To that end, Java 7 introduced several new features/classes in the java.util.concurrency package that allow developers to approach the thread synchronization domain from a high(er) level.  java.util.concurrent.locks.ReentrantLock is more flexible and gives more fine grain control over the scope of locking.  it also performs better.  The advice that I see around the web (including on Stack Overflow) is that ReentrantLock should replace synchronized block in all new code.