SDSU CS 596 Client-Server Programming
Threads

[To Lecture Notes Index]
San Diego State University -- This page last updated March 5, 1996
----------

Contents of Threads Lecture

    1. Threads
      1. Creating Threads
      2. SimpleThread for Use in Future Examples
      3. Thread Scheduling - Preemptive
      4. More Streams
      5. Messages between Threads
      6. Synchronize

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()

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: " + getName() );
        }
    }

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: Thread-4
Message 1From: Thread-4
Message 2From: Thread-4
Message 3From: Thread-4
Message 4From: Thread-4
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: " + 
                                Thread.currentThread().getName() );
        }
    }

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: Thread-4
Message 1 From: Thread-4
Message 2 From: Thread-4
Message 3 From: Thread-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

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() );
            }
        }
    }

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

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
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
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"
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

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 )  {}
            }
        }
    }

// 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

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

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

More Streams


Streams are like Unix pipes

Java has ~17 different Streams

The goal is modularity

Combining streams is very useful

import java.io.*;
import sdsu.io.ASCIIInputStream;

class  StreamExample
    {
    public  static  void  main( String  args[]  ) throws Exception
        {
        File  sourceFile  =  new File( "ReadingFileExample.java" );
        FileInputStream inputFile  = new FileInputStream( sourceFile);

        ASCIIInputStream  fileIn;
        fileIn  =  new  ASCIIInputStream( inputFile );
        fileIn.readWord();
        ASCIIInputStream  standardIn;
        standardIn  =  new  ASCIIInputStream(System.in);
        standardIn.readWord();
        }
    }

Piped Streams

In most streams, one end is a:
file
socket
keyboard


In piped streams both ends are in your program

Useful for filters and for communications between threads
    // Modified from Sun Code
    public static InputStream Up( InputStream source ) {
        PipedOutputStream ps = null;
        PipedInputStream is = null;

        try {
            ASCIIInputStream dis = new ASCIIInputStream( source );
            String input;

            ps = new PipedOutputStream();
            is = new PipedInputStream(ps);
            PrintStream os = new PrintStream( ps );

            while ( ( input = dis.readLine() ) != null ) {
                os.println( input.toUpperCase ) );
            }
            os.close();
        } catch ( Exception e ) {
            System.out.println( "StringUtils reverse: " + e );
        }
        return is;
    }

Messages between Threads


import java.io.*;
import sdsu.io.ASCIIInputStream;
class  ReadThread  extends Thread
    {

    private  ASCIIInputStream  cin;

    public  ReadThread(  String  name,  PipedInputStream  input )
        {
        super( name );
        cin  =  new ASCIIInputStream( input );
        }

    public  void run() 
        {
        try
            {
            System.out.println( "Start " + getName() );
            String  message  =  cin.readWord();
            System.out.println( message +  " From: " + getName() );
            }
        catch  ( Exception  ignored )
            {
            }
        }
    }

// Threads and IO Continued

class  TestIO
    {
    public static void main( String[]  args )  throws Exception
        {

        PipedInputStream  inPipe  =  new PipedInputStream();
        PipedOutputStream  outPipe  =  new PipedOutputStream(inPipe);

        PrintStream  cout  =  new  PrintStream(  outPipe  );

        ReadThread  reader  =  new ReadThread( "Read",  inPipe  );
        reader.setPriority( 6 );   // 5 is normal priority
        reader.start();

        System.out.println( "In Main" );
        cout.println( "Hello" );
        System.out.println( "End" );
        }
    }


Output
Start Read
In Main
End
Hello From: Read

Keyboard IO Blocks!

import sdsu.io.ASCIIInputStream;
class  IOThread  extends Thread
    {
    public  IOThread(  String  name ) {  super( name );  }

    public  void run()
        {
        System.out.println( getName() + "Is starting" );
        System.out.print( "Please Type an integer: " );
        System.out.flush();

        ASCIIInputStream  cin = new ASCIIInputStream(System.in);
        try
            {
            int input = cin.readInt();    // Wait here
            System.out.println( "You typed: " + input );
            }
        catch  ( Exception  ignored )  {}
        }
    }

// Keyboard IO Blocks! Continued
class  TestIOBlocking
    {
    public static void main( String[]  args )  throws Exception
        {
        Thread  worker  =  new SimpleThread( "Worker",  10 );
        IOThread  boss  =  new IOThread( "The Boss" );

        boss.setPriority( 5 );
        worker.setPriority( 5 );   // 5 is normal priority

        worker.start();
        boss.start();
        System.out.println( "End" );
        }
    }


Output
End3 From: Worker
The Boss Is starting4 From: Worker
Please Type an integer: 125 From: Worker
You typed: 126 From: Worker
0 From: Worker7 From: Worker
1 From: Worker8 From: Worker
2 From: Worker9 From: Worker


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
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
        }
    }

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 ) );
            }
        }
    }


// 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() );
        }
    }

// 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 )  {}
            }
        }
    }

// 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
// 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


----------