SDSU CS 596: Client-Server Programming
Spring Semester, 1997
Doc 7, Threads

To Lecture Notes Index
San Diego State University -- This page last updated Feb 13, 1997
----------

Contents of Doc 7, Threads

    1. Threads
      1. Creating Threads
      2. Thread Scheduling - Preemptive
      3. Simple Yield Example
      4. Sleep Example
      5. Suspend and Resume
      6. Join - Waiting for Thread to end
    2. Synchronize
      1. Synchonized and Inheritance
      2. wait and notify
        1. wait - How to use
        2. notify - How to Use

Doc 7, Threads Slide # 1

Threads


Thread is a separate process which shares the same name space as the program that created the thread

Difference from fork()

fork()
Child process gets a copy of parents variables
Relatively expensive to start
Don't have to worry about concurrent access to variables

thread
Child process shares parents variables
Relatively cheap to start
Concurrent access to variables is an issue


Thread Class Methods
activeCount()interrupt() setDaemon(boolean)
checkAccess()interrupted() setName(String)
countStackFrames()isAlive() setPriority(int)
currentThread()isDaemon() sleep(long)
destroy()isInterrupted() sleep(long, int)
dumpStack()join() start()
enumerate(Thread[])join(long) stop()
getName()join(long, int) stop(Throwable)
getPriority()resume() suspend()
getThreadGroup()run() toString()
yeild()


Doc 7, Threads Slide # 2

Creating Threads


There are two different methods for creating a thread
class  SimpleThread  extends Thread
   {
   public  void run()
      {
      for  ( int  count = 0;  count < 4; count++)
         System.out.println( "Message " + count +
                          "From: Mom" );
      }
   }

class  TestThread
   {
   public static void main( String[]  args )
      {
      SimpleThread  parallel  = new SimpleThread();
      System.out.println( "Create the thread");
      parallel.start();
      System.out.println( "Started the thread" );
      System.out.println( "End" );
      }
   }
Output
Create the thread
Started the thread
End
Message 0From: Mom
Message 1From: Mom
Message 2From: Mom
Message 3From: Mom
Message 4From: Mom

Doc 7, Threads Slide # 3
Second Method for Creating a Thread

class  SecondMethod  implements  Runnable
   {
   public  void  run()
      {
      for  ( int  count = 0;  count < 4; count++)
         System.out.println( "Message " + count +  " From: Dad");
      }
   }

class  TestThread
   {
   public static void main( String[]  args )
      {
      SecondMethod  notAThread  = new SecondMethod();
      Thread  parallel  =  new Thread( notAThread );

      System.out.println( "Create the thread");
      parallel.start();
      System.out.println( "Started the thread" );
      System.out.println( "End" );
      }
   }
Output
Create the thread
Started the thread
End
Message 0 From: Dad
Message 1 From: Dad
Message 2 From: Dad
Message 3 From: Dad

Doc 7, Threads Slide # 4
Giving a Thread a Name

class  SecondMethod  implements  Runnable
   {
   public  void  run()
      {
      for  ( int  count = 0;  count < 4; count++)
         System.out.println( "Message " + count +  " From: " + 
                        Thread.currentThread().getName() );
      }
   }

class  TestThread
   {
   public static void main( String[]  args )
      {
      SecondMethod  notAThread  = new SecondMethod();
      Thread  parallel  =  new Thread( notAThread, "Mom" );

      System.out.println( "Create the thread");
      parallel.start();
      System.out.println( "Started the thread" );
      System.out.println( "End" );
      }
   }
Output
Create the thread
Started the thread
End
Message 0 From: Mom
Message 1 From: Mom
Message 2 From: Mom
Message 3 From: Mom

Doc 7, Threads Slide # 5
SimpleThread for Use in Future Examples
class  SimpleThread  extends Thread
   {
   private  int  maxCount =  32;

   public  SimpleThread(  String  name )
      {
      super( name );
      }

   public  SimpleThread(  String  name, int repetitions )
      {
      super( name );
      maxCount  =  repetitions;
      }

   public  SimpleThread(  int repetitions )
      {
      maxCount  =  repetitions;
      }


   public  void run()
      {
      for  ( int  count = 0;  count < maxCount; count++)
         {
         System.out.println( count + " From: " + getName() );
         }
      }
   }


Doc 7, Threads Slide # 6
Show Some Parallelism?

class  TestThread
   {
   public static void main( String[]  args )
      {
      SimpleThread  first      = new SimpleThread( 5 );
      SimpleThread  second  = new SimpleThread( 5 );
      first.start();
      second.start();
      System.out.println( "End" );
      }
   }


Output
End
0 From: Thread-4
1 From: Thread-4
2 From: Thread-4
3 From: Thread-4
4 From: Thread-4
0 From: Thread-5
1 From: Thread-5
2 From: Thread-5
3 From: Thread-5
4 From: Thread-5

Doc 7, Threads Slide # 7

Thread Scheduling - Preemptive

Priorities

A thread is run before other threads with lower priorities
public final static int MIN_PRIORITY = 1
public final static int NORM_PRIORITY = 5
public final static int MAX_PRIORITY = 10


class  TestThread
   {
   public static void main( String[]  args )
      {
      SimpleThread  first      = new SimpleThread( 5 );
      SimpleThread  second  = new SimpleThread( 5 );
      second.setPriority( 8 );
      first.start();
      second.start();
      System.out.println( "End" );
      }
   }

Output
0 From: Thread-5
1 From: Thread-5
2 From: Thread-5
3 From: Thread-5
4 From: Thread-5
0 From: Thread-4
1 From: Thread-4
2 From: Thread-4
3 From: Thread-4
4 From: Thread-4
End

Doc 7, Threads Slide # 8
Thread SchedulingTime-slicing or not time-sliced

Time-slicing
a thread is run for a short time slice and suspended,
resumes only when it gets its next "turn"
threads of the same priority share turns
Java does not specify if the scheduler does time-slicing

Java on Solaris does not time-slice

Non time-sliced threads run until:
they end
they are terminated
they are interrupted
Higher priority threads interrupts lower priority threads
they go to sleep
they block on some call
reading a socket
waiting for another thread
they yield
Methods of Interest

Doc 7, Threads Slide # 9
destroy()sleep(long)
interrupt() sleep(long, int)
join() stop()
join(long) stop(Throwable)
join(long, int) suspend()
yield()
Testing for Time-slicing
class  InfinityThread  extends Thread
   {
   public  void run()
      {
      while ( true )
         System.out.println(  "From: " + getName() );
      }
   }

class  TestThread
   {
   public static void main( String[]  args )
      {
      InfinityThread  first      = new InfinityThread( );
      InfinityThread  second  = new InfinityThread( );
      first.start();
      second.start();
      }
   }


Output if Time-sliced

"From: Thread-5" and "From: Thread-4" will intermix "forever"



Output if not Time-sliced

"From: Thread-4" will repeat "forever"

Doc 7, Threads Slide # 10

Simple Yield Example

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
End
0 From: Thread-4
0 From: Thread-5
1 From: Thread-4
1 From: Thread-5
2 From: Thread-4
2 From: Thread-5
3 From: Thread-4
3 From: Thread-5

Doc 7, Threads Slide # 11

Sleep Example


class  SleepyThread  extends Thread
   {

   public  SleepyThread(  String  name )
      {
      super( name );
      }

   public  void run()
      {
      for  ( int  count = 0;  count < 4; count++)
         {
         System.out.println( count + " From: " + getName() );

         try
            {
            sleep( 5 );   // in  milliseconds
            }

         catch  ( InterruptedException ignored )  {}
         }
      }
   }


Doc 7, Threads Slide # 12
// 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
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


Doc 7, Threads Slide # 13

A Clock Example
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;}
      }
   }


Doc 7, Threads Slide # 14
Using Clock

import sdsu.io.Console;
import java.util.Date;

class Test
   {
   public static void main(String  args[] ) throws Exception
      {
      Clock fast = new Clock( 60 * 60 * 10 );
      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
Thu Feb 13 17:19:11 PST 1997
Type an int 12
Fri Feb 28 17:19:11 PST 1997
Type an int 21
Mon Mar 24 17:19:11 PST 1997
Type an int 12
Thu Apr 10 18:19:11 PDT 1997
Type an int 12
Fri May 02 18:19:11 PDT 1997
Type an int 12

Doc 7, Threads Slide # 15
Setting Priorities

Continuously running parts of the program should have lower-priority than rarer events

User input should have very high priority

A thread that continually updates some data is often set to run at MIN_PRIORITY


Doc 7, Threads Slide # 16

Suspend and Resume

class  Suspended
   {
   public static void main( String[]  args ) throws 
      InterruptedException
      {
      SimpleThread  alert      = new SimpleThread( "Alert" );
      SleepyThread  sleepy  = new SleepyThread( "Sleepy" );
      sleepy.setPriority( 8 );
      alert.start();
      sleepy.start();

      sleepy.suspend();
      System.out.println( "now I can go" );
      Thread.sleep( 4 );
      sleepy.resume();
      }
   }
Output
0 From: Sleepy12 From: Alert26 From: Alert
0 From: Alert13 From: Alert27 From: Alert
1 From: Alert14 From: Alert28 From: Alert
2 From: Alert15 From: Alert29 From: Alert
3 From: Alert16 From: Alert30 From: Alert
4 From: Alert17 From: Alert31 From: Alert
5 From: Alert18 From: Alert3 From: Sleepy
6 From: Alert19 From: Alert
7 From: Alert20 From: Alert
8 From: Alert21 From: Alert
9 From: Alert22 From: Alert
1 From: Sleepy23 From: Alert
now I can go24 From: Alert
10 From: Alert2 From: Sleepy
11 From: Alert25 From: Alert


Doc 7, Threads Slide # 17

Join - Waiting for Thread to end

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

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


Doc 7, Threads Slide # 18

Synchronize


With multiprocessing we need to address mutual exclusion

What happens when two threads access the same:
method?
data?

class  AccessExample
   {
   public  int[]  data  =  new  int[10];

   public  safeCode( int Size,  int  startValue)
      {
      int[]  verySafe  =  new  int[ Size ]; 

      for  ( int  index  = 0; index < Size;  index++ )
         verySafe[ index ]  =  (int ) Math.sin( index * startValue );
      }

   public  dangerousCode( int Size,  int  startValue)
      {
      for  ( int  index  = 0; index < Size;  index++ )
         data[ index ]  =  (int ) Math.sin( index * startValue );
      }
   }

Java uses "Synchronized" code to insure that only one thread at a time will use a section of critical code

Doc 7, Threads Slide # 19
Synchronize Syntax
class  SynchronizeSyntax
   {
   protected  int myValue;
   public  static  int  globalStuff;

   public  synchronized  void  synchronizedMethod()
      {
      myValue++;
      }

   public  ShowSynchronizedBlock(  Vector  criticalData  )
      {
      // Some non-critical code can go here

      synchronized (  criticalData  )
         {
         // put critical code relating to criticalData here
         }

      // More non-critical code can go here
      }

   public  SynchronizedClass(  )
      {
      // Some non-critical code can go here

      synchronized (  getClass()  )
         {
         // put critical code relating to class SynchronizeSyntax
         }

      // More non-critical code can go here
      }
   }

Doc 7, Threads Slide # 20
Synchronized Example
class  Loop
   {
   public  void  doLoop( int size, String name ) 
      {
      for  ( int  count = 0;  count < size; count++)
         {
         System.out.println( count + " From: " + name );
         double wasteTime  =  Math.sin( Math.cos ( count ) );
         }
      }
   }


class  SyncLoop  extends  Loop
   {
   public  synchronized  void  doLoop( int size, String name ) 
      {
      for  ( int  count = 0;  count < size; count++)
         {
         System.out.println( count + " From: " + name );
         double wasteTime  =  Math.sin( Math.cos( count ) );
         }
      }
   }



Doc 7, Threads Slide # 21
// Synchronized Example Continued

class  SimpleThread  extends Thread
   {
   private  int  maxCount;
   private  Loop  myCopyOfLoop;


   public  SimpleThread(  String  name, int count, Loop  copy )
      {
      super( name );
      maxCount  =  count;
      myCopyOfLoop  =  copy;
      }


   public  void  run()
      {
      myCopyOfLoop.doLoop( maxCount, getName() );
      }
   }


Doc 7, Threads Slide # 22
// Synchronized Example Continued

class  SleepyThread  extends Thread
   {
   private  Loop  myCopyOfLoop;
   private  int  maxCount;

   public  SleepyThread(  String  name, int count,  Loop  copy )
      {
      super( name );
      maxCount  =  count;
      myCopyOfLoop  =  copy;
      }


   public  void run()
      {
      for  ( int  count = 0;  count < 4; count++)
         {
         try
            {
            sleep( 5 );   // in  milliseconds
            myCopyOfLoop.doLoop( maxCount, getName() );
            }
         catch  ( InterruptedException ignored )  {}
         }
      }
   }


Doc 7, Threads Slide # 23
// Synchronized Example Continued


class  TestNoSynch
   {
   public static void main( String[]  args ) throws Exception
      {
      Loop  notSafe  =  new Loop();
      SimpleThread  alert;
      SleepyThread  sleepy;

      alert  = new SimpleThread( "Alert", 8, notSafe );
      sleepy  = new SleepyThread( "Sleepy", 2, notSafe );

      sleepy.setPriority( 8 );
      alert.start();
      sleepy.start();
      System.out.println( "End" );
      }
   }

Output
0 From: Alert6 From: Alert
1 From: Alert7 From: Alert
2 From: Alert0 From: Sleepy
0 From: Sleepy1 From: Sleepy
1 From: Sleepy0 From: Sleepy
End1 From: Sleepy
3 From: Alert0 From: Sleepy
4 From: Alert1 From: Sleepy
5 From: Alert


Doc 7, Threads Slide # 24
// Synchronized Example Continued

class  TestSynch
   {
   public static void main( String[]  args ) throws Exception
      {
      Loop  safe  =  new SyncLoop();
      SimpleThread  alert;
      SleepyThread  sleepy;

      alert  = new SimpleThread( "Alert", 8, safe  );
      sleepy  = new SleepyThread( "Sleepy", 2, safe  );

      sleepy.setPriority( 8 );
      alert.start();
      sleepy.start();
      System.out.println( "End" );
      }
   }

Output
0 From: Alert1 From: Sleepy
1 From: AlertEnd
2 From: Alert0 From: Sleepy
3 From: Alert1 From: Sleepy
4 From: Alert0 From: Sleepy
5 From: Alert1 From: Sleepy
6 From: Alert0 From: Sleepy
7 From: Alert1 From: Sleepy
0 From: Sleepy


Doc 7, Threads Slide # 25

Synchonized and Inheritance

class Top
   {
   public void synchronized left()
      {
      // do stuff
      }

   public void synchronized right()
      {
      // do stuff
      }
   }

class Bottom extends Top
   {
   public void left()
      {
      // not synchronized 
      }

   public void right()
      {
      // do stuff not synchronized
      super.right();   // synchronized here
      // do stuff not synchronized
      }

If you want a method in a subclass to be synchronized you must declare it to be synchronized.

Doc 7, Threads Slide # 26
Synchonized and Static Methods

Two threads can not execute synchronized static methods on the same class at the same time.

The lock for a static method has no effect on any of the objects of that class.


Doc 7, Threads Slide # 27

wait and notify

class Queue
   {
   LinkedCell head;
   LinkedCell tail;
   
   public synchronized void append( Object item )
      {
      LinkedCell  newItem = new LinkedCell( item );

      if ( head == null )
         head = newItem;
      else
         tail.append( newItem );

      tail = newItem;
      notify();
      }

   public synchronized Object get( )
      {
      try
         {
         while ( head == null )
            wait();
         }
      catch (InterruptedException threadIsDone )
         {
         return null;
         }
      
      Object returnMe = head.element();
      head = head.next();
      return returnMe;
      }
   }

Doc 7, Threads Slide # 28
wait and notify - Helper
class LinkedCell
   {
   Object cellItem;
   LinkedCell next;

   public LinkedCell( Object value )
      {
      cellItem= value;
      }

   public Object element()
      { 
      return cellItem;
      }

   public void append( LinkedCell nextCell )
      {
      next = nextCell;
      }

   public LinkedCell next()
      { 
      return next; 
      }
   }



Doc 7, Threads Slide # 29
wait and notify - Producer

class Producer extends Thread
   {
   Queue factory;
   int workSpeed;
   
   public Producer( String name, Queue output, int speed )
      {
      setName(name);
      factory = output;
      workSpeed = speed;
      }
   
   public void run()
      {
      try
         {
         int product = 0;
         while (true) // work forever
            {
            System.out.println( getName() + " produced " + product);
            factory.append( getName() + String.valueOf( product) );
            product++;
            sleep( workSpeed);
            }
         }
      catch ( InterruptedException WorkedToDeath )
         { 
         return;
         }
      }
   }
   
   

Doc 7, Threads Slide # 30
wait and notify - Consumer

class Consumer extends Thread
   {
   Queue localMall;
   int sleepDuration;
   
   public Consumer( String name, Queue input, int speed )
      {
      setName(name);
      localMall = input;
      sleepDuration = speed;
      }
   
   public void run()
      {
      try
         {
         while (true) // Shop until you drop
            {
            System.out.println( getName() + " got " + 
                              localMall.get());
            sleep( sleepDuration );
            }
         }
      catch ( InterruptedException endOfCreditCard )
         { 
         return;
         }
      }
   }


Doc 7, Threads Slide # 31
wait and notify - Driver Program

class Test
   {
   public  static  void  main( String  args[] ) throws Exception
      {
      Queue wallmart = new Queue();
      Producer nike = new Producer( "Nike", wallmart, 500 );
      Producer honda = new Producer( "Honda", wallmart, 1200 );
      Consumer valleyGirl = new Consumer( "Sue", wallmart, 400);
      Consumer valleyBoy = new Consumer( "Bob", wallmart, 900);
      Consumer dink = new Consumer( "Sam", wallmart, 2200);
      nike.start();
      honda.start();
      valleyGirl.start();
      valleyBoy.start();
      dink.start();
      }
   }
Output
Nike produced 0Sue got Nike3Honda produced 3
Honda produced 0Nike produced 4Bob got Honda3
Sue got Nike0Sue got Nike4Nike produced 8
Bob got Honda0Honda produced Sue got Nike8
Nike produced 1Bob got Honda2Nike produced 9
Sam got Nike1Nike produced 5Sue got Nike9
Nike produced 2Sue got Nike5Honda produced 4
Sue got Nike2Nike produced 6Bob got Honda4
Honda produced 1Sam got Nike6Nike produced 10
Bob got Honda1Nike produced 7Sue got Nike10
Nike produced 3Sue got Nike7Nike produced 11


Doc 7, Threads Slide # 32

wait - How to use


The thread waiting for a condition should look like:
synchronized void waitingMethod()
   {
   while ( ! condition )
      wait();

   Now do what you need to do when condition is true
   }
Note

Everything is executed in a synchronized method

The test condition is in loop not in an if statement

The wait suspends the thread it atomically releases the lock on the object

Doc 7, Threads Slide # 33

notify - How to Use

synchronized void changeMethod()
   {
   Change some value used in a condition test

   notify();
   }


Doc 7, Threads Slide # 34
wait and notify Methodsin Object

public final void wait(timeout) throws InterruptedException
Causes a thread to wait until it is notified or the specified timeout expires.
Parameters:
timeout - the maximum time to wait in milliseconds
Throws: IllegalMonitorStateException
If the current thread is not the owner of the Object's monitor.
Throws: InterruptedException
Another thread has interrupted this thread.

public final void wait(timeout, nanos) throws InterruptedException
public final void wait() throws InterruptedException

public final void notify()
public final void notifyAll()
Notifies all of the threads waiting for a condition to change. Threads that are waiting are generally waiting for another thread to change some condition. Thus, the thread effecting a change that more than one thread is waiting for notifies all the waiting threads using the method notifyAll(). Threads that want to wait for a condition to change before proceeding can call wait(). The method notifyAll() can only be called from within a synchronized method.


----------