SDSU CS 596 Java Programming
Fall Semester, 1998
Threads part 2
To Lecture Notes Index
© 1998, All Rights Reserved, SDSU & Roger Whitney
San Diego State University -- This page last updated 13-Nov-98

Contents of Doc 20, Threads part 2


References


The Java Programming Language , 2 nd Ed. Arnold & Gosling, Addison-Wesley, 1998

Concurrent Programming in Java: Design Principles and Patterns , Doug Lea, Addison-Wesley, 1997

Cancellable Activities, Doug Lea, October 1998, http://gee.cs.oswego.edu/dl/cpj/cancel.html

Java 1.2b4 on-line documentation


Listen Here!S-nov2 2mins Doc 20, Threads part 2 Slide # 2

Thread Control


So far we have just started threads and let them run independently. Threads often have to work together. One thread may need the result of some computation of another thread. The first thread will have to wait until the second one has completed the computation. On a single processor, you need to make sure that one thread does not consume all the CPU cycles, leaving other threads waiting for their turn.

A thread can be in one of three states: executing (running), runnable (but not executing), not runnable. On a multi-processor machine more than one thread may be executing at the same time. A thread that is waiting for another thread, suspended, or sleeping is not runnable.

Methods of Interest
destroy()
join()
stop()
interrupt()
join(long)
stop(Throwable)
interrupted()
join(long, int)
suspend()
isInterrupted()
sleep(long)
yield()

sleep(long, int)



Listen Here!S-nov2 1min Doc 20, Threads part 2 Slide # 3
Threads Run Once

Once a thread's run method ends, the thread can not be restarted. You can call the thread's run method directly, but that just sequentially executes that method.

class  SimpleThread  extends Thread {
   public void run() {
      System.out.println(  "I ran" );
   }
}

public class Test  {
   public static void main( String args[] ) throws Exception {
      SimpleThread onceOnly = new SimpleThread();
      onceOnly.setPriority( 6 );
      onceOnly.start();
      System.out.println( "Try restart");
      onceOnly.start();
      System.out.println( "The End");
   }
}
Output
I ran
Try restart
The End

Listen Here!S-nov2 3mins, Q-nov5 1min Doc 20, Threads part 2 Slide # 4

Yield

Sending the "yield()" method to a thread moves it from the executing state to the runnable state. Often the executing thread sends the "yield()" method to itself. This allows other runnable threads of the same priority a chance to execute.

class  YieldThread  extends Thread {
   public  void run() {
      for  ( int  count = 0;  count < 4; count++) {
         System.out.println( count + "From: " + getName() );
         yield();
      }
   }
}
class  TestThread {
   public static void main( String[]  args )  {
      YieldThread  first      = new YieldThread();
      YieldThread  second  = new YieldThread();
      first.start();
      second.start();
      System.out.println( "End" );
   }
}
Output - Single and Multiple Processors
End
0From: Thread-2
0From: Thread-3
1From: Thread-2
1From: Thread-3
2From: Thread-2
2From: Thread-3
3From: Thread-2
3From: Thread-3

Listen Here!S-nov2 1min Doc 20, Threads part 2 Slide # 5

Sleep

The sleep() method moves a thread to the not runnable state for specified length of time. At the end of that time, the thread is moved to the runnable state. If it has a higher priority than the current executing thread, the executing thread is moved to the runnable state and the just awakened thread becomes the executing thread.

class  SleepyThread  extends Thread
   {
   int maxCount = 4;
   public  SleepyThread(  String  name, int count )
      {
      super( name );
      maxCount = count;
      }
   public  void run()
      {
      for  ( int  count = 0;  count < 4; count++)
         {
         System.out.println( count + " From: " + getName() );
         try
            {
            sleep( 5 );   // in  milliseconds
            }
         catch  ( InterruptedException ignored )  {}
         }
      }
   }

Listen Here!S-nov4 4mins, S-nov2 1min Doc 20, Threads part 2 Slide # 6
// Sleep Example Continued

class  TestSleep
   {
   public static void main( String[]  args )
      {
      SimpleThread  alert    = new SimpleThread( "Alert", 32 );
      SleepyThread  sleepy  = new SleepyThread( "Sleepy", 32 );
      sleepy.setPriority( 8 );
      alert.start();
      sleepy.start();
      System.out.println( "End" );
      }
   }
Output (read down first)
0 From: Sleepy17 From: Alert
0 From: Alert18 From: Alert
1 From: Alert19 From: Alert
2 From: Alert20 From: Alert
3 From: Alert21 From: Alert
4 From: Alert22 From: Alert
5 From: Alert23 From: Alert
6 From: Alert24 From: Alert
7 From: Alert25 From: Alert
8 From: Alert26 From: Alert
9 From: Alert27 From: Alert
10 From: Alert28 From: Alert
11 From: Alert2 From: Sleepy
12 From: Alert29 From: Alert
13 From: Alert30 From: Alert
14 From: Alert31 From: Alert
1 From: Sleepy3 From: Sleepy
End
15 From: Alert
16 From: Alert


Listen Here!S-nov2 1min Doc 20, Threads part 2 Slide # 7

A Clock Example
Using the sleep method and a thread, we can make a clock. The following clock can be used in a simulation. It allows us to simulate a given number of days in an hour.
import java.util.Date;
class Clock extends Thread
   {
   static int millisecondsHour = 1000 * 60 * 60;
   static long millisecondsPerDay = millisecondsHour * 24;
   
   int millSecondsPerSimDay;
   Date simDate = new Date();
   public Clock( int simDaysPerHour )
      {
      millSecondsPerSimDay  = millisecondsHour / simDaysPerHour;
      setPriority( Thread.MAX_PRIORITY );
      }
   
   public String toString() { return simDate.toString(); }
      
   public void run()
      {
      try
         {
         while (true)
            {
            // Advance one sim day
            long simTime = simDate.getTime();
            simDate.setTime( simTime + millisecondsPerDay);
            // wait until next day
            sleep( millSecondsPerSimDay );
            }
         }
      catch ( InterruptedException simulationOver )
         { return;}
      }
   }

Listen Here!S-nov2 2mins Doc 20, Threads part 2 Slide # 8
Using the Clock

import sdsu.io.Console;
class Test
   {
   public static void main(String  args[] ) throws Exception
      {
      Clock fast = new Clock( 7 * 52 * 60 );
      fast.start();
      for ( int k = 0; k < 5; k++ )
         {
         System.out.println( fast.toString());
         Console.readInt( "Type an int" );
         }
      fast.stop();
      }   
   }
Output
rohan 24-> java Test
Tue Nov 03 09:37:55 PST 1998
Type an int 12
Sun Nov 29 09:37:55 PST 1998
Type an int 32
Fri Jan 29 09:37:55 PST 1999
Type an int 12
Sat Apr 17 10:37:55 PDT 1999
Type an int 10
Thu Jan 20 09:37:55 PST 2000
Type an int 10

Listen Here!S-nov4 2mins, S-nov2 2mins Doc 20, Threads part 2 Slide # 9

Join - Waiting for Thread to end


If thread A sends the "join()" method to thread B, then thread A will be "not runnable" until thread B's run methods ends. At that time thread A becomes runnable.

class  Godot
   {
   public static void main( String[]  args ) throws 
      InterruptedException
      {
      SimpleThread  lowly      = new SimpleThread( "Lowly" );
      lowly.setPriority( 1 );
      lowly.start();
      System.out.println( "now I can go" );
      lowly.join();
      System.out.println( "Done" );
      }
   }
Output (Read down first)

now I can go11 From: Lowly23 From: Lowly
0 From: Lowly12 From: Lowly24 From: Lowly
1 From: Lowly13 From: Lowly25 From: Lowly
2 From: Lowly14 From: Lowly26 From: Lowly
3 From: Lowly15 From: Lowly27 From: Lowly
4 From: Lowly16 From: Lowly28 From: Lowly
5 From: Lowly17 From: Lowly29 From: Lowly
6 From: Lowly18 From: Lowly30 From: Lowly
7 From: Lowly19 From: Lowly31 From: Lowly
8 From: Lowly20 From: LowlyDone
9 From: Lowly21 From: Lowly
10 From: Lowly22 From: Lowly


Listen Here!S-nov4 5mins Doc 20, Threads part 2 Slide # 10

Ending Thread Execution


A thread ends when its run method ends. At times program needs to permanently stop a running thread. For example, when a user uses a browser to access a web page. The browser will open a new network connection in a separate thread. If the user then cancels the request, the browser may need to "kill" the thread doing the down load.

Suspend, Resume, Stop, destroy

Java has some thread methods that will stop threads. However, these methods are not safe! They could leave your program in an inconsistent state or cause deadlock. Suspend, resume and stop do exist, but are not safe. They are deprecated in JDK 1.2. Destroy, while listed in the on-line API, was never implemented. It throws a NoSuchMethodError() in JDK 1.2.

These methods are deprecated in JDK 1.2 because they are not thread safe

Start avoiding these methods now!

What replaces Stop?
It turns out that there is no safe way to implement a method that will stop a thread in general. Doug Lea recommends a multiphase approach. First, use interrupt. If that fails, try starving the thread. If that also fails, giving the thread the minimum priority to reduce its impact. If these all fail and the situation calls for drastic action, then one can use stop(), perform clean up operations, then exit the program.


Listen Here!S-nov4 9mins Doc 20, Threads part 2 Slide # 11

Forcing a Thread to Quit - Using interrupt()

A thread can perform a block of operations then check to see if it is interrupted. If it has been interrupted, then it can take "proper" action. Sometimes proper action is to clean up, then quit. Sometimes proper action may be to "reset itself" to be available to run again later. In the example below the sleep() method is throwing the InterruptedException.

class  NiceThread  extends Thread {
   public void run() {
      while ( !isInterrupted() ) {
         System.out.println(  "From: " + getName()  );
      }
      System.out.println( "Clean up operations" );
   }
}

public class Test {
   public static void main(String args[]) throws InterruptedException{
      NiceThread  missManners  = new NiceThread( );
      missManners.setPriority( 2 );
      missManners.start();
      Thread.currentThread().sleep( 5 ); // Let other thread run
      missManners.interrupt();
   }
}
Output
From: Thread-3
From: Thread-3
From: Thread-3
From: Thread-3
From: Thread-3
Clean up operations

Listen Here!S-nov4 3mins Doc 20, Threads part 2 Slide # 12
Interrupt Methods in java.lang.Thread

void interrupt()
Sent to a thread to interrupt it

boolean isInterrupted()
Sent to a thread to see if it has been sent the interrupt() method
Returns true if the thread has been sent the interrupt() method

static boolean interrupted()
Sent to the current thread to see if it has been sent the interrupt() method
Returns true if the thread has been sent the interrupt() method
Clears the interrupt flag in the current thread


Listen Here!S-nov4 1min, S-nov4 3mins Doc 20, Threads part 2 Slide # 13
Using Thread.interrupted

This example uses the test Thread.interrupted() to allow the thread to be continue execution later. Note that thread uses suspend() after it has made sure that all data is safe. This is harder to do in real life than the simple example here indicates. Using wait would be better here, but we have not covered wait() yet.

class  RepeatableNiceThread  extends Thread {
   public void run() {
      while ( true ) {
         while ( !Thread.interrupted() )
            System.out.println(  "From: " + getName()  );
         System.out.println( "Clean up operations" );
         suspend();
      }
   }
}

public class Test {
   public static void main(String args[]) throws InterruptedException{
      RepeatableNiceThread  missManners  = 
            new RepeatableNiceThread( );
      missManners.setPriority( 2 );
      missManners.start();
      Thread.currentThread().sleep( 5 );
      missManners.interrupt();
      missManners.resume();
      Thread.currentThread().sleep( 5 );
      missManners.interrupt();
   }
}

Listen Here!S-nov4 3mins Doc 20, Threads part 2 Slide # 14

Interrupt and sleep, join & wait


Let thread A be in the not runnable state due to being sent either the sleep(), join() or wait() methods. Then if thread A is sent the interrupt() method, it is moved to the runnable state and InterruptedException is raised in thread A.

In the example below, NiceThread puts itself to sleep. While asleep it is sent the interrupt() method. The code then executes the catch block.

class  NiceThread  extends Thread {
   public void run() {
      try {
         while ( !isInterrupted() ) {
            System.out.println(  "From: " + getName()  );
            sleep( 5000 );
         }
         System.out.println( "Clean up operations" );
      } catch ( InterruptedException interrupted ) {
         System.out.println( "In catch" );
      }      
   }
}
public class Test {
   public static void main( String args[] )  {
      NiceThread  missManners  = new NiceThread( );
      missManners.setPriority( 6 );
      missManners.start();
      missManners.interrupt();
   }
}
Output
From: Thread-1
In catch

Listen Here!S-nov4 3mins Doc 20, Threads part 2 Slide # 15
Who Sends sleep() is Important

Since main sends the sleep method, not the thread itself, the InterruptedException is not thrown.

public class Test  {
   public static void main( String args[] ) {
      try {
         NiceThread  missManners  = new NiceThread( );
         missManners.setPriority( 1 );
         missManners.start();
         missManners.sleep( 5000);
         missManners.interrupt();
      } catch ( InterruptedException interrupted ) {
         System.out.println( "Caught napping" );
      }
   }
}
class  NiceThread  extends Thread {
   public void run() {
      try {
         while ( !isInterrupted() ) {
            System.out.println(  "From: " + getName()  );
         }
         System.out.println( "Clean up operations" );
      } catch ( Exception interrupted ) {
         System.out.println( "In catch" );
      }      
   }
}
Output
From: Thread-1
From: Thread-1
From: Thread-1
From: Thread-1
Clean up operations

Listen Here!S-nov4 3mins Doc 20, Threads part 2 Slide # 16

IO Blocks


A read() on an inputstream or reader blocks. Once a thread calls read() it will not respond to interrupt() (or much else) until the read is completed. This is a problem when a read could take a long time: reading from a socket or the keyboard. If the input is not forth coming, the read() could block forever. NonBlockingInputStream on the next slide will timeout and respond to interrupt.


Listen Here!S-nov4 4mins Doc 20, Threads part 2 Slide # 17
NonBlockingInputStream

public class NonBlockingInputStream extends FilterInputStream {
   private int pollDuration;
   private long timeout;
   public NonBlockingInputStream( InputStream input, int pollDelay, 
                                       long timeout ){
      super( input );
      pollDuration = pollDelay;
      this.timeout = timeout;
   }
   public int read() throws IOException {
      pollInput();
      return in.read();
   }
   public int read(byte inputBuffer[], int offset, int length) throws IOException {
      pollInput();
      return in.read( inputBuffer, offset, length);
   }
   private void pollInput() throws IOException {
      long startTime = System.currentTimeMillis();
      while (  in.available() <= 0 ) 
         try  {
            if (  System.currentTimeMillis() - startTime >= timeout )
               throw new IOException( "Timeout on read");
            Thread.sleep( pollDuration );
         } catch ( InterruptedException stopReading ) {
            throw new InterruptedIOException( "read() interrupted" );
         }
   }
}

Copyright © 1998 SDSU & Roger Whitney, 5500 Campanile Drive, San Diego, CA 92182-7700 USA.
All rights reserved.

visitors since 02-Nov-98