This chapter covers:
- Recognizing and avoiding deadlocks and race conditions
- Using explicit locks
- Using lock-free synchronization
- Designing immutable classes
The plan for this chapter is to make your implementation thread-safe. For a class to be thread-safe, multiple threads should be able to interact with the objects of that class with no explicit synchronization.
In other words, a thread-safe class takes care of the synchronization issues. The clients can just freely invoke any class method, even simultaneously on the same object, with no adverse effects. The design-by-contract methodology presented in chapter 5 allows you to precisely characterize what an adverse effect would be: the violation of a post-condition or an invariant.
Compared with other functional defects, lack of thread safety can go unnoticed for much longer. Some synchronization defects become apparent only in special circumstances, when the timing and the scheduling are just right (or wrong) for a race condition to mess up the state of an object or for a deadlock to freeze your program. That’s one more reason to read this chapter carefully!
This chapter assumes you have familiarity with basic multi-threading in Java, such as creating threads and using synchronized blocks to achieve mutual exclusion. As a self-test, consider taking exercise 1 at the end of this chapter. It’ll remind you the main properties of the synchronized keyword.