Last week we released our Core Java Concurrency Refcard, an indispensable reference for the performance-conscious Java developer. Alex Miller, the author of the card, took some time out to answer some of my questions about the card, and the importance of concurrency.
DZone: Hi Alex, could you introduce yourself please?
Alex Miller: I'm a developer in St. Louis, Missouri, a husband, and a father of three. I work remotely for Terracotta, which is based in San Francisco. At Terracotta, I'm a tech lead trying to keep up with a team of crazy smart developers based in India, Belgium, West Virginia, Seattle, and San Francisco. I've been working in Java for about 12 years and worked at BEA and MetaMatrix before Terracotta. I tend to drift towards building server-side platforms so that seems to be my calling.
I also like to do some writing and speaking on the side. I present at a lot of regional user groups and some bigger conferences like JavaOne, QCon, CodeMash, etc. I write occasionally for publications like JavaWorld and DZone and keep up the blogging and tweeting.
Also, I like nachos.
DZone: What are your experiences with concurrency in Java?
Alex Miller: I got seriously interested in concurrency about two years ago when I joined Terracotta. I had read Java Concurrency in Practice (as every Java developer should) but I was only working with concurrent Java programs occasionally. At Terracotta, we build a high-scale clustered JVM platform and concurrency is everywhere - from the application-side library to the server, to clustered and distributed data structures and algorithms. So I've really been immersed in it for a couple years now. While I feel like I have a good grasp of the basics, I also feel like there is always more to learn and I never stop challenging my own assumptions.
DZone: When you look at code, what are the repeating bugs in threading that you see? And how can those issues be addressed?
Alex Miller: I did a whole talk about Java concurrency bugs at JavaOne this year. I think a number of the most common problems I see relate back to issues of visibility. If fields are changed outside synchronization, those changes are simply not guaranteed to be seen in any other thread, ever. This problem is so tricky because programs may appear to work fine on some machines or most of the time but will fail in potentially confusing ways when run under load on server-class machines.
Some concrete problems that come up all the time are shared mutable instances of classes like SimpleDateFormat or GregorianCalendar (usually typed as DateFormat and Calendar respectively). These classes are very tempting to construct, save in a static, and reuse. However, they contain mutable state that is modified while performing calculations like parsing and formatting or date arithmetic. If multiple threads use the same instance without locking, incorrect answers will inevitably result.
DZone: What are the most important things to consider when writing well- threaded applications?
Alex Miller: In Java, concurrency is really all about managing access (with locks) to shared, mutable state. Start from the data - decide which data is shared and how access to that data will be protected. If at all possible encapsulate the locking with the data; for example use the excellent thread-safe collections in java.util.concurrent.
As Brian Goetz says when dealing with shared, mutable state, consider ways to NOT share or NOT mutate. You can avoid sharing by using data that is thread-confined or using ThreadLocal. You can avoid mutating by making objects immutable and following more functional programming techniques.
Whatever you decide, document what you've done in the code using the threading annotations defined in Java Concurrency in Practice. FindBugs can be used to verify those assertions and find many common concurrency issues.
And finally, test on real hardware with real loads. Use profilers, thread dumps, Visual VM, and other tools to verify your assumptions and find your bottlenecks.
DZone: Are there any better options for handling concurrency outside of the core Java classes?
Alex Miller: Well first I'd like to say that I wish more people made better use of what is already offered by java.util.concurrent! I would highly recommend using Locks, the various thread coordination classes like CyclicBarrier and CountdownLatch, and Executors to clean up a lot of old code. In general, any time you are explicitly creating Threads, using Thread.join() or wait()/notify(), there are probably better alternatives in the concurrency library.
For concurrency geeks like me, this is a wonderful time as there is a cornucopia of work occurring on alternative languages and concurrency paradigms. In Java, JDK 7 will contain a new library from Doug Lea called fork / join that is designed to support fine-grained parallelism of divide-and-conquer sorts of problems. That will be a great addition to the executors and other tools we have currently for coarse-grained parallelism in the JDK. There has been a lot of buzz recently about the "actor" model of concurrency which is a form of message-passing. I wrote about some alternatives for actors on the JVM earlier this year and some newer libraries like Actorom have popped up even since then.
From a language perspective, I've been trying to learn as much as possible about languages like Clojure (persistent data structures, functional programming, software transactional memory), Scala (actors), Erlang (immutability, functional programming, actors), and F# (functional programming). All of these languages are pushing beyond the boundaries of how concurrency is done in Java, searching for better abstractions that make concurrent programming easier and safer.