Every Java thread has a priority that helps the operating system determine the order in which threads are scheduled. Java priorities are in the range between MIN_PRIORITY (a constant of 1) and MAX_PRIORITY (a constant of 10). Informally, threads with higher priority are more important to a program and should be allocated processor time before lower-priority threads. However, thread priorities cannot guarantee the order in which threads execute. By default, every thread is given priority NORM_PRIORITY (a constant of 5). Each new thread inherits the priority of the thread that created it.
[Note: These constants (MAX_PRIORITY, MIN_PRIORITY and NORM_PRIORITY) are declared in the Thread class. It is recommended that you do not explicitly create and use Thread objects to implement concurrency, but rather use the Runnable interface (which is described in Section 23.4). The THRead class does contain some static methods that are useful, as you will see later in this chapter.]
Most Java platforms support timeslicing, which enables threads of equal priority to share a processor. Without timeslicing, each thread in a set of equal-priority threads runs to completion (unless it leaves the runnable state and enters the waiting or timed waiting state, or gets interrupted by a higher-priority thread) before other threads of equal priority get a chance to execute. With timeslicing, even if the thread has not finished executing when the quantum expires, the processor is taken away from that thread and given to the next thread of equal priority, if one is available.
The job of an operating system's thread scheduler is to determine which thread runs next. One simple implementation of the thread scheduler keeps the highest-priority thread running at all times and, if there is more than one highest-priority thread, ensures that all such threads execute for a quantum each in round-robin fashion. Figure 23.3 illustrates a multi-level priority queue for threads. In the figure, assuming a single-processor computer, threads A and B each execute for a quantum in round-robin fashion until both threads complete execution. This means that A gets a quantum of time to run. Then B gets a quantum. Then A gets another quantum. Then B gets another quantum. This continues until one thread completes. The processor then devotes all its power to the thread that remains (unless another thread of that priority becomes ready). Next, thread C runs to completion (assuming that no higher-priority threads arrive). Threads D, E and F each execute for a quantum in round-robin fashion until they all complete execution (again assuming that no higher-priority threads arrive). This process continues until all threads run to completion.
Figure 23.3. Thread-priority scheduling.
(This item is displayed on page 1058 in the print version)
Portability Tip 23.2
Thread scheduling is platform dependentan application that uses multithreading could behave differently on separate Java implementations.
When a higher-priority thread enters the ready state, the operating system generally preempts the currently running thread (an operation known as preemptive scheduling). Depending on the operating system, higher-priority threads could postponepossibly indefinitelythe execution of lower-priority threads. Such indefinite postponement often is referred to more colorfully as starvation.
Portability Tip 23.3
When designing applets and applications that use threads, you must consider the threading capabilities of all the platforms on which the applets and applications will execute.
J2SE 5.0 provides higher-level concurrency utilities to hide some complexity and make multithreaded programs less error prone (though they are still certainly complex). Thread priorities are still used behind the scenes to interact with the operating system, but most programmers who use J2SE 5.0 multithreading will not be concerned with setting and adjusting thread priorities. You can learn more about priorities and threading at java.sun.com/j2se/5.0/docs/api/java/lang/Thread.html.