The class libraries include a number of state-dependent classesthose having operations with state-based preconditionssuch as FutureTask, Semaphore, and BlockingQueue. For example, you cannot remove an item from an empty queue or retrieve the result of a task that has not yet finished; before these operations can proceed, you must wait until the queue enters the "nonempty" state or the task enters the "completed" state.
The easiest way to construct a state-dependent class is usually to build on top of an existing state-dependent library class; we did this in ValueLatch on page 187, using a CountDownLatch to provide the required blocking behavior. But if the library classes do not provide the functionality you need, you can also build your own synchronizers using the low-level mechanisms provided by the language and libraries, including intrinsic condition queues, explicit Condition objects, and the AbstractQueuedSynchronizer framework. This chapter explores the various options for implementing state dependence and the rules for using the state dependence mechanisms provided by the platform.
Part I: Fundamentals
Part II: Structuring Concurrent Applications
Cancellation and Shutdown
Applying Thread Pools
Part III: Liveness, Performance, and Testing
Avoiding Liveness Hazards
Performance and Scalability
Testing Concurrent Programs
Part IV: Advanced Topics
Building Custom Synchronizers
Atomic Variables and Nonblocking Synchronization
The Java Memory Model