I’ve recently purchased a copy of Java Concurrency in Practice. I was always a little bit scared of threaded code, but we have a small amount at work, so I figured I’d better get my head around it. Wow. The big takeaway from the book was that I was nowhere near scared enough. Concurrency is hard.
But it’s not all bad news. Java 5 introduced java.util.concurrent—a set of abstractions for dealing with concurrency at a higher level. Chapters 5 and 6 are an overview of these facilities. There’s extensive coverage of the new data structures like ConcurrentHashMap as well as a very detailed exploration of what the new Executor and ExecutorService can do for you. That’s as well as looking at things like latches, queues and so on.
Chapter 7 was a detailed exploration of the issues surrounding Thread.interrupt() and ensuring that your threads can shut down properly. Java’s threading system is cooperative—you can’t stop a thread, you have to ask it to stop. This is harder to get right than it looks. Incidentally, much of the same discussion is on the web as Java theory and practice: Dealing with InterruptedException (by the same author, Brian Goetz).
These chapters were probably the most immediately useful parts of the book for me. I put it down and rewrite the threaded portions of my application using ConcurrentHashMap, ExecutorService and using interrupt()
for cancellation. And I saw improvements. Where the threads had previously not shut correctly 100% of the time, they now worked just fine. In general, I feel a lot happier using the higher level abstractions. Or maybe that should be “less uneasy about having cocked it up”.
Stepping back a moment, the rest of the book is still very useful. The first part is a grounding of both concurrency and concurrency in Java. It’s all illustrated with very good code examples1. This really taught me about visibility as a threading issue, which I hadn’t previously been aware of at all (and it pointed me straight at a bug in my own code). i.e.
class Foo extends Thread { private boolean done = false; public synchronized void setDone(boolean done) { this.done = done; } public void run() { while (!done) { // … } } }
Spot the problem here? Because read access to done
isn’t synchronized
, an update from another thread might not be noticed. Ooops. (and yes, it’s better to implements Runnable
rather than extends Thread
[and yes, I should be using Thread.interrupt()
rather than my own flag]).
Later chapters continue to give excellent, clear advice. I’ve never done (or needed to do) Swing programming, but there appears to be a good discussion of the issues involved in ensuring that you only do GUI actions within the confines of a single thread.
One chapter which really blew me away was the testing chapter. I had absolutely no idea how to go about testing thread safety. The clues flew in abundance at me from the pages however. I confess I haven’t written any tests yet, but I at least have an idea of where to start now…
The later chapters are “advanced topics”. They seemed like cogent explanations, but as an absolute beginner, they weren’t too relevant just yet. I can see I’ll be coming back to the book soon enough, however.
Overall, I reckon this is one of those “must own” books, if you go anywhere near Java and threads.
1 Nothing is more off-putting than bad code examples. I mean, you’re meant to be an expert, right? Brian outlined how to avoid errors in code on his blog.