Meantime

Document Sample
Meantime Powered By Docstoc
					1.1 Java Multithreading

1.1.1     Line Tracing Robot

        Line tracing robot is a robot that searches for a black line and then tries to follow it.
The hardware of the robot consists of two motors and two light sensors. The light sensors
detect the color of the floor and the robot makes turns based on the sensor readings. The
robot stops when the View button is pressed.

       In this section we will discuss two different implementations of the software:
sequential and concurrent implementations. We will use LejOS and Java for SE 532.

1.1.2     A Sequential Design and Implementation

        The following program shows a sequential design and implementation of the
software for the line-tracing robot with LeJOS and Java. The design follows a round-robin
software architecture. It polls the readings of the light sensors and makes decision based on
the readings. The program can be divided into three functional segments. The first segment
is to initialize the light sensors and motors. The second segment is a while loop used to
search for the black line. It compares the readings of the sensors and it keeps moving
forward until one of the sensors has a reading of black color (reading is less than 35). The
third segment is to make necessary turns based on the readings of the light sensors to follow
the black line found in the second segment. This is a done with a while loop, and at the end
of each loop it reads the status of the Run button. If the button is pressed, it turns off the
motors and sensors and terminates the execution.

        import josx.platform.rcx.*;

           public class Tracer implements ButtonListener {

              private   static final int BLACK_COLOR = 35;
              private   static final int MOTOR_SPEED = 7;
              private   int color1 = 0;
              private   int color2 = 0;
              private   boolean running = true;

              public static void main(String args[]) throws
           InterruptedException {
                 Tracer roboDemo = new Tracer();
              }

              public Tracer() throws InterruptedException {
                 // First segment: initialization

           Sensor.S1.setTypeAndMode(SensorConstants.SENSOR_TYPE_LIGHT,
                 SensorConstants.SENSOR_MODE_PCT);
                 Sensor.S1.activate();

           Sensor.S2.setTypeAndMode(SensorConstants.SENSOR_TYPE_LIGHT,
                 SensorConstants.SENSOR_MODE_PCT);
      Sensor.S2.activate();

      Button.RUN.addButtonListener(this);

      LCD.clear();   /*   Clear the LCD display   */

      Motor.A.setPower(MOTOR_SPEED);
      Motor.B.setPower(MOTOR_SPEED);

      // second segment: search for the black line
      color1 = Sensor.S1.readValue();
      color2 = Sensor.S2.readValue();
      while (color1 > BLACK_COLOR && color2 > BLACK_COLOR) {
         TextLCD.print("srch");
         Motor.A.backward();
         Motor.B.forward();
         color1 = Sensor.S1.readValue();
         color2 = Sensor.S2.readValue();
         Thread.sleep(100);
      }

      // third segment: follow the black line.
      while (true) {

         while (running) {
            color1 = Sensor.S1.readValue();
            color2 = Sensor.S2.readValue();
            if (color1 <= BLACK_COLOR && color2 <=
BLACK_COLOR) {
               Motor.A.backward();
               Motor.B.forward();
               TextLCD.print("fwrd");
            }
            else if (color1 <= BLACK_COLOR) {
               Motor.A.forward();
               Motor.B.forward();
               TextLCD.print("left");
            }
            else {
               Motor.A.backward();
               Motor.B.backward();
               TextLCD.print("rght");
            }
            Thread.sleep(50);
         }
         TextLCD.print("stop");
         Thread.sleep(100);
      }
   }

   public void buttonPressed(Button b)
   {
      if (!running) {
         running = true;
      }
      else {
         stopMotors();
                 }
              }
              public void buttonReleased(Button b) {}

              private void stopMotors() {
                 running = false;
                 Motor.A.stop();
                 Motor.B.stop();
              }
         }




         The program controls the robot pretty well. When the robot is placed in the center
of the black belt of the Lego test paper, it moves forward until it finds the black belt and
then it follows it.

1.1.3   A Concurrent Design and Implementation

       A thread in Java is like a process; it can be executed independent of other threads. A
thread may be designed to perform a simple, atomic task.

        Java provides the Thread class for thread creation, control, and termination. A user-
defined thread is normally a subclass of Thread. The most important method of Thread is
run(), which is to be overridden by the user-defined thread to the real work assigned to it.
The start() method of Thread is to start the execution of the thread. It first requests the
JVM to allocate memory space for the new thread and then invokes the run() method of the
thread. The following is a Java program, TwoHello, that displays on the LCD greetings to
“Tom” and “Clark” at the rate of once every 3 seconds and one every 2 seconds,
respectively. The TwoHello class extends Thread and it defines its own run() method. The
run() method prints the name stored in the object at the specified rate. The main() function
instantiates two instances of the TwoHello class and then starts their execution by calling
their start() methods.

        import josx.platform.rcx.*;

        public class TwoHello extends Thread {
           private String name;
           private int delay;

             public TwoHello(String name, int delay) {
                this.name = name;
                this.delay = delay;
             }
             public void run() {
                try {
                   for (int i=0; i < 5; i++) {
                      TextLCD.print(name);
                      sleep(delay*1000);
                   }
                } catch (InterruptedException e) {
                   return;
              }
           }
           public static void main(String argv[]) {
              TwoHello h1 = new TwoHello("Tom", 3);
              TwoHello h2 = new TwoHello("Clark", 2);

                h1.start();
                h2.start();
           }
       }

After a new thread is created, the parent and the child threads execute in the same memory
space. In other words, global variables are all accessible to both threads.

        Now let us take a look how we can use threads in real-time systems design. For the
black line-tracing robot, we used a sequential program that polls the readings of the sensors,
and based on them makes a decision on turns and loops back. Now let us design the robot
using threads. Assume there is an object; call it sensorState that stores the current readings
of the two light sensors. Then logically a sensor monitor, call it SensorMonitor , can be used
to read the sensors and store the values in sensorState . Reading sensor values and storing
them in the object would the only responsibility of the SensorMonitor. We also need a
driver that can read the sensor value (stored in sensorState , which is analogous to the
dashboard of the car) and make turns. Let us call this driver MotorController . Its
responsibility is also very straightforward, reading the sensor values from sensorState and
then determines which way to go. There is another function that is used to stop the robot, a
monitor to monitor whether a button (in this example, the View button) is pressed or not.
Once it is pressed, the robot should stop, i.e., stop the motors and turn off the sensors.


               Left Motor                      Sensor State
                                                                          Left Sensor



                            MotorController                    SensorMonitor



                                                                         Right Sensor
               Right Motor                    ButtonMonitor



                                               Button View



        The following program implements this design with three threads. The SensorState
class defines the sensor state. It declares two public data members for the values of the left
and right sensors, so they can be accessed directly by the motor controller and sensor
monitor.

    /**
    import josx.platform.rcx.*;

    class SensorState {
       public int left;
       public int right;
       public SensorState(int l, int r)
       {
          left = l; right = r;
       }
    }

    class SensorMonitor extends Thread {
       private SensorState sensorState;
       private Sensor left;
       private Sensor right;

       public SensorMonitor(SensorState ss, Sensor left, Sensor
    right) {
          this.left = left;
          this.right = right;
          this.sensorState = ss;

           left.setTypeAndMode(SensorConstants.SENSOR_TYPE_LIGHT,
              SensorConstants.SENSOR_MODE_PCT);
           left.activate();
           right.setTypeAndMode(SensorConstants.SENSOR_TYPE_LIGHT,
              SensorConstants.SENSOR_MODE_PCT);
           right.activate();
        }
        public void run() {
           try {
              while (true) {
                 sensorState.left = left.readValue();
                 sensorState.right = right.readValue();
                 sleep(25);

                    if (isInterrupted()) {break;}
               }
           }
           catch (Exception e) {}
        }
        public void stopSensors() {
           left.passivate();
           right.passivate();
        }
    }
    public class TracerThread extends Thread {

        private    static final int BLACK_COLOR = 35;
        private    static final int MOTOR_SPEED = 7;
        private    SensorState sensorState;
        private    Motor left, right;
    public TracerThread(SensorState ss, Motor left, Motor right)
    {
       this.sensorState = ss;
       this.left = left;
       this.right = right;
       left.setPower(MOTOR_SPEED);
       left.setPower(MOTOR_SPEED);

    }
    public void run() {
       try {
          LCD.clear(); /*   Clear the LCD display   */

          while (sensorState.left > BLACK_COLOR &&
                sensorState.right > BLACK_COLOR) {
             TextLCD.print("srch");
             left.backward();
             right.B.forward();
             Thread.sleep(100);
          }
          while (true) {
             if (sensorState.left <= BLACK_COLOR &&
                sensorState.right <= BLACK_COLOR) {
                left.backward();
                right.forward();
                TextLCD.print("fwrd");
             }
             else if (sensorState.left <= BLACK_COLOR) {
                left.forward();
                right.forward();
                TextLCD.print("left");
             }
             else {
                left.backward();
                right.backward();
                TextLCD.print("rght");
             }
             Thread.sleep(25);
             if (isInterrupted()) {
                break;
             }
          }
       }
       catch (Exception e) {}
}
    public void stopMotors() {
        left.stop();
       right.stop();
    }
    public static void main(String args[])
          throws InterruptedException {
       SensorState sensorState = new SensorState(99, 99);
       SensorMonitor monitor =
          new SensorMonitor(sensorState, Sensor.S1, Sensor.S2);
       monitor.start();
       TracerThread tracer =
                 new TracerThread(sensorState, Motor.A, Motor.B);
              tracer.start();
              ButtonMonitor buttonMonitor =
                 new ButtonMonitor(monitor, tracer);
              Button.VIEW.addButtonListener(buttonMonitor);
           }
        }
        class ButtonMonitor implements ButtonListener {
           private SensorMonitor monitor;
           private TracerThread tracer;

           public ButtonMonitor(SensorMonitor monitor, TracerThread
        tracer) {
              this.monitor = monitor;
              this.tracer = tracer;
           }
           public void buttonPressed(Button b)
           {
              tracer.stopMotors();
              tracer.interrupt();
              monitor.stopSensors();
              monitor.interrupt();
           }
           public void buttonReleased(Button b) {}
        }

1.1.4     Scheduling and Priority Assignment

        LeJOS employs a preemptive priority-based scheduling algorithm for threads. There
are 10 different priority levels from 1 to 10 with 10 as the highest priority. With preemptive
priority scheduling, when a thread with a higher priority than the current running thread is
ready for execution, it preempts the execution of the current running thread and takes t he
CPU. For threads with same priority, LeJOS employs the round-robin scheduling algorithm
(The size of time quantum is unknown.) Each thread runs for up to one time quantum. If it
does not release the CPU by the end of the allocation time quantum, LeJOS preempts its
execution and select next thread of the same priority for execution for up to a new time
quantum.

          The Thread class provides following methods for priority control.

          1. public final int getPrioity(); return the priority of the thread, and

          2. public final void setPriority(int newPriority); sets the priority of the thread to
             newPriority . It throws IllegalArgumentException if newPriority is not in the
             range of [MIN_PRIORITY=1, MAX_PRIORITY=10] inclusive. When a child
             thread is created, the child inherits the parent thread’s priority.

          The Thread class also provides methods for scheduling control.

          1. public static void sleep(long milliseconds) throws InterruptedException;
             puts the calling thread to sleep for at least milliseconds. The “at least” here
            means that the thread may not wake up and/or execute in the exact specified
            time. Why? When a thread is in sleep, it no longer competes for CPU time until
            it wakes up. If the thread is interrupted (will be discussed shortly) while it is in
            sleep, an InterruptedException will be thrown and the thread wakes up and
            returns from sleep(). InterruptedException must be caught or re-thrown by
            the function in which sleep() is invoked.

       2. public static void sleep(long milliseconds, int nanoseconds) throws
          InterruptedException; is the same as the above sleep method exception that
          this method can specify the number of nanoseconds to be delayed in addition
          to the specified milliseconds. Nanoseconds must be in the range of [0, 999999]
          inclusive.

       3. public static void yield(); causes the calling thread to yield or release the CPU
          so that other runnable threads with the same priority level can have a chance
          using the CPU. The yielding thread may acquire the CPU right away it is the only
          thread in its priority level.

        To determine the priority for each thread we need to determine the criticalness and
urgency of each thread in relation to other threads. For the line tracing robot,
ButtonMonitor should have the highest priority among the threads is because, when the
button is pressed, we don’t wish the robot to move any further so it should be executed
whenever it is ready or the button is pressed. SensorMonitor should have the second
highest priority since we want the MotorController to use latest readings from the sensors.
MotorController has the lowest priority among the three. ButtonMonitor ,
SensorMonitor , and MotorController have the priority assigned 10, 9, and 8, respectively.
The following code segment shows the modified version of the main() method of the
TracerThread class.

        public static void main(String args[])
              throws InterruptedException {
           SensorState sensorState = new SensorState(99, 99);
           SensorMonitor monitor =
              new SensorMonitor(sensorState, Sensor.S1, Sensor.S2);

            monitor.setPriority(9);

            monitor.start();
            TracerThread tracer =
               new TracerThread(sensorState, monitor);

            tracer.setPriority(8);

            tracer.start();
            ButtonMonitor buttonMonitor =
               new ButtonMonitor(monitor, tracer);
            Button.VIEW.addButtonListener(buttonMonitor);
        }
        Observant readers may have noticed that the ButtonMonitor’s priority is not set in
the code shown above. Then how is it done? The point I am trying to make here is that,
when we design real-time applications, we must know how the underlining operating system
(in our example, LeJOS) and what the operating system provides us as system designer and
implementer. LeJOS executes all event listeners in a thread at the highest priority
(MAX_PRIORITY = 10) when the listened event occurs. Thus, although the above code
does not set ButtonMonitor’s priority, its buttonPressed() method will be executed with the
highest priority by LeJOS, the underling operating system.

1.1.5   The Double Buffer Technique

        The program shown above seems work fine at first look. However, with further
inspection, we will find that MotorController may not always use the sensor readings
correctly. The SensorMonitor has a higher priority than MotorController, it may preempt
the execution of MotorController . When such a preemption occurs right after
MotorController had just read the left sensor value and before the right sensor,
MotorController would use a value of the left sensor that gathered 25 milliseconds earlier
than the right sensor. The following diagram illustrates what may happen.

        MotorController                            SensorMonitor                                      time

                                                             SensorState.left = left.readV alue();
                                                             SensorState.right = right.readValue();     t1
               // do something
               SensorState.left < 35
               (1st part of the while condition)
                                                             SensorState.left = left.readValue();
                                                             SensorState.right = right.readValue();
                                                                                                        t2
               SensorState.right <35
               (2nd part of the while condition)




                     running                       blocked                     ready


      At time t1 (on the right side) SensorMonitor read the readings and stored them in
SensorState . When MotorController executed its second while loop sometime after t1, it
checked the left sensor value first which was gathered at t1, and before it checked the right
sensor value, it is preempted by SensorMonitor at t2, which read a new pair of sensor
readings. When MotorController got the CPU back after t2, it checked the right sensor
value, which was collected at t2. Thus the MotorController used the reading of the left
sensor collected at t1 and the reading of the right sensor at t2.

       There are at least three ways to solve the problem. One is called the double buffer
technique, another is to use Java synchronized methods, and the last is to use semaphores,
which will be discussed in next section. With the double buffer technique, instead of using
one buffer for the shared data between two threads, two buffers and a flag are used and the
flag is used to indicate which thread is to use which of the two buffers.

        The following shows a modified version of the SensorState. It contains an array of
two buffers ( buf[2]) for the two buffers and an integer variable, switch, to indicate which
buffer the sensor monitor is supposed to store next pair of readings. Two methods are
introduced, setValues(), for the sensor monitor to store new readings, and getValues(), for
the motor controller to read the stored readings. The setValues() checks the value of
switch to determine where to store the readings. The getValues() also checks the value of
switch to find out which buffer it is supposed to read from, and after reading the values it
changes switch to point to the other buffer. In essence, the sensor monitor would use the
same buffer for new readings until the motor controller has used the other buffer. For the
program to work, it is obvious MotorController and SensorMonitor both need to be
modified to accommodate the changes made to SensorState.

    class Buffer {
       public int left;
       public int right;
    }
    class SensorState {
       public Buffer buf[2];
       private int switch;

         SensorState(int left, int right) {
            buf[0] = new Buffer();
            buf[1] = new Buffer();
            buf[0].left = buf[1].left = left;
            buf[0].right = buf[1].right = right;
            this.switch = 0;
         }
         public void setValues(int left, int right) {
            if (switch == 0) {
               buf[0].left = left;
               buf[0].right = right;
            }
            else {
               buf[1].left = left;
               buf[1].right = right;
            }
         }
         public void getValues(Buffer buf) {
            if (switch == 0) {
               buf.left = buf[1].left;
               buf.right = buf[1].right;
            }
            else {
               buf.left = buf[0].left;
               buf.right = buf[0].right;
            }
            switch = (switch + 1) % 2;
         }
    };
1.1.6     Monitors and Java Synchronized Methods

        The double buffer solution ensures that the motor controller always uses a pair of
sensor readings that are gathered at the same time. However, it may not always use the pair
of the most recent readings. Why?

        Java implements the high-level synchronization primitive called monitors, proposed
by Hoare and Brinch Hansen. A monitor consists of procedures and data members and it
can only be accessed through its procedures. One critical property monitors have is that the
procedures of the monitor can be executed by only one thread at a time. If another thread
tries to call a procedure it has to wait until the thread completes the procedure. In other
words, each monitor has a lock . When a thread tries to execute a procedure, the lock is
checked. If the lock is not locked, then the thread locks the lock and then executes the
procedure and possibly other procedures as well. If the lock is locked, then the calling thread
is put to sleep on the monitor’s lock. When the thread, which possesses the lock, completes
the procedure, it unlocks the lock and one of the waiting threads may acquire the lock and
execute the procedure. Thus mutual exclusion to the access to a monitor is achieved by only
allowing one thread to execute procedures of the monitor at a time.

          Java implements monitors by using synchronized methods and private data
members. To make objects of a Java class monitors we can declare its data members private
to ensure they are not accessible directly by clients and qualify its methods with the keyword
synchronized to ensure that they can only be executed mutually exclusively by one thread at
a time. Like monitors, an object has a lock for all synchronized methods. The thread that
first tries to execute a synchronized method acquires the lock and all other threads that try
to execute any synchronized method of the object have to wait until the lock is unlocked.
Please note that a thread may execute a non-synchronized method of the object no matter
whether another thread possesses the lock of the object or not. Thus, if one wishes all
methods of an object to be mutual exclusive, then one must declare a ll the methods
synchronized.

       The following code shows how to implement the SensorState as monitor. Both
setValues() and getValues() are qualified with the keyword synchronized. Thus, when
MotorController is reading the sensor values by executing getValues(), SensorMonitor
has to wait if it wants to write to SensorState . When MotorController completes its
readings, SensorMonitor can write to SensorState.

        class Buffer {
           public int left;
           public int right;
        };
        class SensorState {
           private Buffer buf

           SensorState(int left, int right) {
              Buf = new Buffer();
              buf.left = left;
              buf.right = right;
           }
           public synchronized void setValues(int left, int right) {
                 buf.left = left;
                 buf.right = right;
             }
             public synchronized void getValues(Buffer buf) {
                buf.left = left;
                buf.right = right;
             }
        };

1.1.7        Using Semaphores for Synchronization

        The following code shows an implementation of SensorState using a semaphore.
With this semaphore, the setValues() and getValues() methods are executed mutually
exclusively.

        class Buffer {
        public:
           int left;
           int right;
        };
        class SensorState {
        public:
           Buffer buf;
           Semaphore mutex;

             SensorState(int left, int right) {
                buf.left = left;
                buf.right = right;
                mutex = new Semaphore(1);
             }
             void setValues(int left, int right) {
                mutex->down();
                buf.left = left;
                buf.right = right;
                mutex->up();
             }
             void getValues(int *left, int *right) {
                mutex->down();
                &left = buf.left;
                &right = buf.right;
                mutex->up();
             }
        };



         Many real-time operating systems provide semaphores as a standard facility for
process or thread synchronization. POSIX (Portable Operating System Interfaces) specifies
a set of standard semaphore functions. Java does not have semaphores. In order to use
semaphores in Java, we can implement semaphores as monitors as will be discussed in next
section.

1.1.8        Thread Synchronization
        Synchronized methods guarantee mutual exclusion between threads that try to access
the same object through synchronized methods. However, threads may need to
communicate with each other in addition to mutual exclusion. For example, a thread, after
acquiring the lock, may find it cannot successfully complete the needed method, for
example, insufficient fund for withdrawal in banking applications. Then we may want the
thread to wait, releasing the CPU, until the condition, more fund is added for the banking
example, is changed.

       Java provides variations of three methods in the Thread class for thread
synchronization.

         1. The wait() methods causes the calling thread to be blocked, releasing the CPU.

         2. The notify() and notifyAll() methods can be used to inform waiting threads that
            the condition(s) they are waiting on has been changed. The difference between
            notify() and notifyAll() is that the former selects only one of the waiting threads
            (it is not defined which thread will be selected from the waiting threads.) and
            marks it runnable and the latter marks all the waiting threads runnable. Since
            threads may wait on different conditions, the selected thread by notify() may not
            be an one whose waiting condition becomes true now, and thus it is
            recommended that notifyAll() be used.

         For the banking example we mentioned, we can design withdraw and deposit
         methods as follows:

    class BankingAccount {
       private double balance;

         public synchronized withdraw(double amount)
               throws InterruptedException {
            while (balance < amount) wait();
            balance = balance - amount;
         }
         public synchronized void deposit() {
            balance = balance + amount;
            notifyAll();
         }
    };



        Note that the wait() is enclosed in a while loop, which checks the waiting condition.
This is necessary. Enclosing it in the while loop ensures that the thread would check the
condition again when it wakes up. If it were not in the while loop, for example, in an if-then
structure, the thread, after waking up from a notifyAll() , may continue to complete its
withdrawal even when the deposit did not raise the balance to a level sufficient for this
withdrawal. Another case for the necessary while loop is that, notifyAll() marks all waiting
threads runnable. The first executed thread after waking up may have withdrawn enough to
make it insufficient for subsequent withdrawals. Without the while loop to check the
condition again, all the subsequent withdrawals would all be carried out.
         Synchronized methods, wait(), and notify()/notifyAll() may be used together to
implement semaphores as shown below.

    class Semaphore {
       private int value;

         Semaphore(int value) {
            if (value < 0) throws
               new IllegalArgumentException(value + “<0”);
            this.value = value;
         }
         public synchronized down() throws InterruptedException {
            while (value < 1) wait();
            value = value –1;
         }
         public synchronized void up() {
            value = value + 1;
            notifyAll();
         }
    };



         Other variations of wait() include:

         1. public final void wait(long timeout) throws InterruptedException; causes
            the calling thread to wait until it is notified (by notify() or notifyAll()) or the
            timeout expires. When timeout = 0, wait until notified.

         2. public   final void wait(long timeout, int nanoseconds) throws
            InterruptedException; is the same as above except the timeout can be specifed
            at nanoseconds in addition to milliseconds.

         3. public final void wait() throws InterruptedException; is equivalent to
            wait(0);

         All variations of wait and notify must be enclosed in synchronized blocks.
Notification by notify() and notifyAll() is not remembered, if a thread decides to wait after
the last notification, the earlier notification has no effect on it.

         Other thread-related methods defined in Thread include:

         1. public void interrupt(); sets the interrupted flag. If the thread is asleep, it will
            wake up and an InterruptedException will be thrown. For the line tracing
            example, monitor.interrupt(); is executed by the ButtonMonitor to interrupt
            the SensorMonitor (referenced by monitor ).

         2. public static boolean interrupted(); and public final boolean
            isInterrupted(); return true if the interrupt flag of the thread has been set. In
            the line tracing example, the SensorMonitor uses “if (isInterrupted( )) {
            break; }“ to check whether it has been interrupted or not by ButtonMonitor .
        3. public final boolean isAlive(); returns true if the thread is still alive, not
            terminated yet.

        4. public final void join() throws InterruptedException; and public final void
           join(long timeout) throws InterruptedException cause the calling thread to
            wait until waited thread has terminated. It is currently not implemented by
            LeJOS.

1.1.9   Thread States

        During its life a thread goes through a sequence of states from created to
terminated. The following is called the state transition diagram for threads. When an object
of the class Thread or a subclass of Thread is created, a new thread is created and it is in
created state. After the start() method of Thread is executed, the thread enters ready state.
In readIBy state the thread waits to be selected by the scheduler to use the CPU. When it is
chosen, it goes to running state, using the CPU. From running state, it may go to one of
several different states. If the running thread runs out of its allocated CPU time, for
example, if the JVM employs a round-robin scheduling algorithm, it goes back to ready
state, waiting to be selected again for execution again by the scheduler. If it executes the
yield() method to release the CPU for other threads with the same priority to execute, it
goes back to ready also. If another thread with priority higher than the running thread, the
running thread goes to ready if the JVM employs a preemptive priority based scheduling
algorithm.


                                              created


                                                      start()

                                                  ready




                                              running


                      waiting                                           blocked




                                       sleeping            terminated




       If the running thread calls wait(), it goes to waiting state and it stays there until it is
awakened up by a notify() or notifyAll() , and then it goes to ready, waiting for the CPU.
The running thread may call sleep() to delay its execution for a period of time, which puts
the thread to sleeping state. It wakes up and goes back to ready when the sleep timer
expires. When a sleeping thread wakes up, it may not be scheduled for execution right away.
It is put in the ready queue until it is its turn for using the CPU. That is why the time
specified as the sleep period is minimal for the thread to be executed again. The running
thread may request for I/O, for example from the keyboard, and if the input or output
requested is not ready, the thread is put to blocked state. When the input or output is ready,
it wakes up and goes to ready state waiting for execution. Normally, a thread eventually
completes its execution and goes to terminated state, where it waits for the JVN garbage
collector to reclaim its allocated memory and other resources.

				
DOCUMENT INFO