Newsletter sign-up
View all newsletters

Enterprise Java Newsletter
Stay up to date on the latest tutorials and Java community news posted on JavaWorld

Sponsored Links

Optimize with a SATA RAID Storage Solution
Range of capacities as low as $1250 per TB. Ideal if you currently rely on servers/disks/JBODs

Modern threading: A Java concurrency primer

Understanding Java threads in a post-JDK 1.4 world

  • Print
  • Feedback

Page 6 of 7

 

When good threads go bad ... good programmers make them better

There are two ways of constructing a software design. One way is to make it so simple that there are obviously no deficiencies. And the other way is to make it so complicated that there are no obvious deficiencies. -- C.A.R. Hoare

Hoare's words about the complications of coding seems to apply with special force to multithreading, with the result that many programmers simply shun thread-based code. Most of us can't do without the responsiveness and performance improvements of concurrency, however, especially as software systems evolve onto multicore architectures.

There's no getting around the reality that multithreading is hard. Worse, you might have heard it said that threads are a bad idea, meaning, prone to difficulty.

Some Java developers try to mitigate the hazards of thread programming by trading it in for newer (or just different) styles. Message-passing models expressed in terms of actors and agents eliminate many of the difficulties of shared state and synchronization. So, in a different way, do closures, which come baked into Java 7. The popularity of these alternative concurrency models in Java-related languages like Clojure has amplified their familiarity in the Java community proper.

Still, you might prefer to work with the standard Java threading architecture. As your applications grow more sophisticated, you'll need to learn not only how to launch runnables, but also to synchronize thread execution, communicate between threads, and manage thread lifetimes. With a little effort and the well-established design techniques discussed below you can make your multithreaded code as understandable and reliable as any other Java source.

Loose coupling

If you are going to stick with the Java Threads API and java.util.concurrent, what can you do to reduce the hazards of multithreading? First, develop your own sense of functional style. You know to minimize use of goto and global variables; in much the same way, design your Runnables to be as simple and loosely coupled as possible. "Loose coupling" here has several aspects:

  • Share as little state as possible
  • Minimize side-effects and emphasize immutable objects
  • Use standard design patterns (like Subscribe-Publish) to manage shared resources
  • Minimize inter-thread coordination
  • Simplify the lifespans of threads

Write testable code

Make your threads testable. A conventional application might build in facilities to ensure not just code coverage, but the precise results of "edge cases": does the program behave correctly when a limit is reached? When within one unit of the limit? In the same way, construct your multithreaded application to exercise threads under reproducible, salient conditions: with only a single worker thread operating; with two threads, started in either order; with more threads than the test host has cores; with controllable simulated loads; and so on.

Debug your code

Next, learn how to debug multithreaded applications. Studying best practices for debugging will improve your code measurably. See Esther Schindler's "Learning and improving your debugging skills" for a collection of valuable tips and exercises that will improve your Java debugging techniques.

  • Print
  • Feedback

Resources

Threads programming

Thread synchronization

Locks and monitors

Testing and debugging threads

Threads & alternatives