At any time, a thread is said to be in one of several thread states that are illustrated in the UML state diagram in Fig. 23.1. A few of the terms in the diagram are defined in later sections.
Figure 23.1. Thread life-cycle UML state diagram.
A new thread begins its life cycle in the new state. It remains in this state until the program starts the thread, which places the thread in the runnable state. A thread in this state is considered to be executing its task.
Sometimes a thread transitions to the waiting state while the thread waits for another thread to perform a task. Once in this state, a thread transitions back to the runnable state only when another thread signals the waiting thread to continue executing.
A runnable thread can enter the timed waiting state for a specified interval of time. A thread in this state transitions back to the runnable state when that time interval expires or when the event it is waiting for occurs. Timed waiting threads cannot use a processor, even if one is available. A thread can transition to the timed waiting state if it provides an optional wait interval when it is waiting for another thread to perform a task. Such a thread will return to the runnable state when it is signaled by another thread or when the timed interval expireswhichever comes first. Another way to place a thread in the timed waiting state is to put the thread to sleep. A sleeping thread remains in the timed waiting state for a designated period of time (called a sleep interval) at which point it returns to the runnable state. Threads sleep when they momentarily do not have work to perform. For example, a word processor may contain a thread that periodically writes a copy of the current document to disk for recovery purposes. If the thread did not sleep between successive backups, it would require a loop in which it continually tests whether it should write a copy of the document to disk. This loop would consume processor time without performing productive work, thus reducing system performance. In this case, it is more efficient for the thread to specify a sleep interval (equal to the period between successive backups) and enter the timed waiting state. This thread is returned to the runnable state when its sleep interval expires, at which point it writes a copy of the document to disk and reenters the timed waiting state.
A runnable thread enters the terminated state when it completes its task or otherwise terminates (perhaps due to an error condition). In the UML state diagram in Fig. 23.1, the terminated state is followed by the UML final state (the bull's-eye symbol) to indicate the end of the state transitions.
At the operating-system level, Java's runnable state actually encompasses two separate states (Fig. 23.2). The operating system hides these two states from the Java Virtual Machine (JVM), which only sees the runnable state. When a thread first transitions to the runnable state from the new state, the thread is in the ready state. A ready thread enters the running state (i.e., begins executing) when the operating system assigns the thread to a processoralso known as dispatching the thread. In most operating systems, each thread is given a small amount of processor timecalled a quantum or timeslicewith which to perform its task. When the thread's quantum expires, the thread returns to the ready state and the operating system assigns another thread to the processor (see Section 23.3). Transitions between these states are handled solely by the operating system. The JVM does not "see" these two statesit simply views a thread as being in the runnable state and leaves it up to the operating system to transition threads between the ready and running states. The process that an operating system uses to decide which thread to dispatch is known as thread scheduling and is dependent on thread priorities (discussed in the next section).
Figure 23.2. Operating system's internal view of Java's runnable state.
Introduction to Computers, the Internet and the World Wide Web
Introduction to Java Applications
Introduction to Classes and Objects
Control Statements: Part I
Control Statements: Part 2
Methods: A Deeper Look
Arrays
Classes and Objects: A Deeper Look
Object-Oriented Programming: Inheritance
Object-Oriented Programming: Polymorphism
GUI Components: Part 1
Graphics and Java 2D™
Exception Handling
Files and Streams
Recursion
Searching and Sorting
Data Structures
Generics
Collections
Introduction to Java Applets
Multimedia: Applets and Applications
GUI Components: Part 2
Multithreading
Networking
Accessing Databases with JDBC
Servlets
JavaServer Pages (JSP)
Formatted Output
Strings, Characters and Regular Expressions
Appendix A. Operator Precedence Chart
Appendix B. ASCII Character Set
Appendix C. Keywords and Reserved Words
Appendix D. Primitive Types
Appendix E. (On CD) Number Systems
Appendix F. (On CD) Unicode®
Appendix G. Using the Java API Documentation
Appendix H. (On CD) Creating Documentation with javadoc
Appendix I. (On CD) Bit Manipulation
Appendix J. (On CD) ATM Case Study Code
Appendix K. (On CD) Labeled break and continue Statements
Appendix L. (On CD) UML 2: Additional Diagram Types
Appendix M. (On CD) Design Patterns
Appendix N. Using the Debugger
Inside Back Cover