Thread Scheduler – Concurrency: Part I

Thread Scheduler

Schedulers in JVM implementations usually employ one of the following two strategies, which come into play in the RUNNABLE state:

  • Preemptive scheduling

If a thread with a higher priority than the current running thread moves to the READY substate, the current running thread can be preempted (moved from the RUNNING substate to the READY substate) to let the higher-priority thread execute.

  • Time-sliced or round-robin scheduling

A running thread is allowed to execute for a fixed length of time in the RUNNING substate, after which it moves to the READY substate to await its turn to run again.

It should be emphasized that thread schedulers are implementation- and platform-dependent; therefore, how threads will be scheduled is unpredictable, at least from platform to platform.

Starting a Thread

After a thread has been created, the thread is in the NEW state (Figure 22.5). Only after its start() method has been called, can the thread do useful work. This method is asynchronous—that is, it returns immediately. The newly created thread transits to the READY substate, waiting its turn to execute on the CPU at the discretion of the thread scheduler. The getState() method on this thread will return the value Thread.State.RUNNABLE. For a thread that is created but not started, the getState() method will return the value Thread.State.NEW. Details of creating and starting a thread were covered in an earlier section (p. 1370).

Figure 22.5 Starting a Thread

Running and Yielding

Once in the READY substate, the thread is eligible for running—that is, it waits for its turn to get CPU time. The thread scheduler decides which thread runs and for how long. Figure 22.6 illustrates the transitions between the READY and RUNNING substates. The thread transits from the READY substate to the RUNNING substate when it is its turn to run. The getState() method on this thread will return the value Thread.State.RUNNABLE.

A call to the static method yield(), defined in the Thread class, may cause the current thread in the RUNNING substate to transit to the READY substate. If this happens, the thread is then at the mercy of the thread scheduler as to when it will run again. It is possible that if there are no threads in the READY substate, this thread can continue executing. If there are other threads in the READY substate, their priorities can influence which thread gets to execute.

As with the setPriority() method, the yield() method is also an advisory method, and therefore comes with no guarantees that the JVM will honor the call. A call to the yield() method does not affect any locks that the thread might hold.

Figure 22.6 Running and Yielding

By calling the static method yield(), the running thread gives other threads in the READY substate a chance to run. A typical example where this can be useful is when a user has given some command to start a CPU-intensive computation, and has the option of cancelling it by clicking a CANCEL button. If the computation thread hogs the CPU and the user clicks the CANCEL button, chances are that it might take awhile before the thread monitoring the user input gets a chance to run and take appropriate action to stop the computation. A thread running such a computation should do the computation in increments, yielding between increments to allow other threads to run. This is illustrated by the following run() method:

Click here to view code image

public void run() {
  try {
    while (!done()) {
      doLittleBitMore();
      Thread.yield();                 // Current thread yields.
    }
  } catch (InterruptedException ie) { // Clean up if the thread is interrupted.
    doCleaningUp();
  }
}

Leave a Reply

Your email address will not be published. Required fields are marked *