of threads introduces additional safety hazards not present in single-threaded programs. Similarly, the use of threads introduces additional forms of
liveness failure that do not occur in single-threaded programs.
While safety means "nothing bad ever happens", liveness concerns the complementary goal that "something good eventually happens". A liveness
failure occurs when an activity gets into a state such that it is permanently unable to make forward progress. One form of liveness failure that can
occur in sequential programs is an inadvertent infinite loop, where the code that follows the loop never gets executed. The use of threads
introduces additional liveness risks. For example, if thread A is waiting for a resource that thread B holds exclusively, and B never releases it, A will
wait forever. Chapter 10 describes various forms of liveness failures and how to avoid them, including deadlock (Section 10.1 ), starvation
(Section 10.3.1 ), and livelock (Section 10.3.3 ). Like most concurrency bugs, bugs that cause liveness failures can be elusive because they
depend on the relative timing of events in different threads, and therefore do not always manifest themselves in development or testing.
1.3.3. Performance Hazards
Related to liveness is performance . While liveness means that something good eventually happens, eventually may not be good enough—we
often want good things to happen quickly. Performance issues subsume a broad range of problems, including poor service time, responsiveness,
throughput, resource consumption, or scalability. Just as with safety and liveness, multithreaded programs are subject to all the performance
hazards of single-threaded programs, and to others as well that are introduced by the use of threads.
In well designed concurrent applications the use of threads is a net performance gain, but threads nevertheless carry some degree of runtime
overhead. Context switches —when the scheduler suspends the active thread temporarily so another thread can run—are more frequent in
applications with many threads, and have significant costs: saving and restoring execution context, loss of locality, and CPU time spent scheduling
threads instead of running them. When threads share data, they must use synchronization mechanisms that can inhibit compiler optimizations, flush
or invalidate memory caches, and create synchronization traffic on the shared memory bus. All these factors introduce additional performance
costs; Chapter 11 covers techniques for analyzing and reducing these costs.
1.4. Threads are Everywhere
Even if your program never explicitly creates a thread, frameworks may create threads on your behalf, and code called from these threads must be
thread-safe. This can place a significant design and implementation burden on developers, since developing thread-safe classes requires more care
and analysis than developing non-thread-safe classes.
Every Java application uses threads. When the JVM starts, it creates threads for JVM housekeeping tasks (garbage collection, finalization) and a
main thread for running the main method. The AWT (Abstract Window Toolkit) and Swing user interface frameworks create threads for managing
user interface events. Timer creates threads for executing deferred tasks. Component frameworks, such as servlets and RMI create pools of
threads and invoke component methods in these threads.
If you use these facilities—as many developers do—you have to be familiar with concurrency and thread safety, because these frameworks create
threads and call your components from them. It would be nice to believe that concurrency is an "optional" or "advanced" language feature, but the
reality is that nearly all Java applications are multithreaded and these frameworks do not insulate you from the need to properly coordinate access
to application state.
When concurrency is introduced into an application by a framework, it is usually impossible to restrict the concurrency-awareness to the
framework code, because frameworks by their nature make callbacks to application components that in turn access application state. Similarly, the
need for thread safety does not end with the components called by the framework—it extends to all code paths that access the program state
accessed by those components. Thus, the need for thread safety is contagious.
Frameworks introduce concurrency into applications by calling application components from framework threads. Components
invariably access application state, thus requiring that all code paths accessing that state be thread-safe.
The facilities described below all cause application code to be called from threads not managed by the application. While the need for thread
safety may start with these facilities, it rarely ends there; instead, it ripples through the application.
Timer. Timer is a convenience mechanism for scheduling tasks to run at a later time, either once or periodically. The introduction of a Timer can
complicate an otherwise sequential program, because TimerTask s are executed in a thread managed by the Timer , not the application. If a
TimerTask accesses data that is also accessed by other application threads, then not only must the TimerTask do so in a thread-safe manner, but
so must any other classes that access that data . Often the easiest way to achieve this is to ensure that objects accessed by the TimerTask are
themselves thread-safe, thus encapsulating the thread safety within the shared objects.
Servlets and JavaServer Pages (JSPs). The servlets framework is designed to handle all the infrastructure of deploying a web application and
dispatching requests from remote HTTP clients. A request arriving at the server is dispatched, perhaps through a chain of filters, to the appropriate
servlet or JSP. Each servlet represents a component of application logic, and in high-volume web sites, multiple clients may require the services of
the same servlet at once. The servlets specification requires that a servlet be prepared to be called simultaneously from multiple threads. In other
words, servlets need to be thread-safe.
Even if you could guarantee that a servlet was only called from one thread at a time, you would still have to pay attention to thread safety when