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
- Threads
- Creating Threads
- SimpleThread for Use in Future Examples
- Thread Scheduling - Preemptive
- More Streams
- Messages between Threads
- Synchronize
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() |
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
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 |
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: Sleepy | 17 From: Alert |
0 From: Alert | 18 From: Alert |
1 From: Alert | 19 From: Alert |
2 From: Alert | 20 From: Alert |
3 From: Alert | 21 From: Alert |
4 From: Alert | 22 From: Alert |
5 From: Alert | 23 From: Alert |
6 From: Alert | 24 From: Alert |
7 From: Alert | 25 From: Alert |
8 From: Alert | 26 From: Alert |
9 From: Alert | 27 From: Alert |
10 From: Alert | 28 From: Alert |
11 From: Alert | 2 From: Sleepy |
12 From: Alert | 29 From: Alert |
13 From: Alert | 30 From: Alert |
14 From: Alert | 31 From: Alert |
1 From: Sleepy | 3 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: Sleepy | 12 From: Alert | 26 From: Alert |
0 From: Alert | 13 From: Alert | 27 From: Alert |
1 From: Alert | 14 From: Alert | 28 From: Alert |
2 From: Alert | 15 From: Alert | 29 From: Alert |
3 From: Alert | 16 From: Alert | 30 From: Alert |
4 From: Alert | 17 From: Alert | 31 From: Alert |
5 From: Alert | 18 From: Alert | 3 From: Sleepy |
6 From: Alert | 19 From: Alert | |
7 From: Alert | 20 From: Alert | |
8 From: Alert | 21 From: Alert | |
9 From: Alert | 22 From: Alert | |
1 From: Sleepy | 23 From: Alert | |
now I can go | 24 From: Alert | |
10 From: Alert | 2 From: Sleepy | |
11 From: Alert | 25 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 go | 11 From: Lowly | 23 From: Lowly |
0 From: Lowly | 12 From: Lowly | 24 From: Lowly |
1 From: Lowly | 13 From: Lowly | 25 From: Lowly |
2 From: Lowly | 14 From: Lowly | 26 From: Lowly |
3 From: Lowly | 15 From: Lowly | 27 From: Lowly |
4 From: Lowly | 16 From: Lowly | 28 From: Lowly |
5 From: Lowly | 17 From: Lowly | 29 From: Lowly |
6 From: Lowly | 18 From: Lowly | 30 From: Lowly |
7 From: Lowly | 19 From: Lowly | 31 From: Lowly |
8 From: Lowly | 20 From: Lowly | Done |
9 From: Lowly | 21 From: Lowly | |
10 From: Lowly | 22 From: Lowly | |
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;
}
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
End | 3 From: Worker |
The Boss Is starting | 4 From: Worker |
Please Type an integer: 12 | 5 From: Worker |
You typed: 12 | 6 From: Worker |
0 From: Worker | 7 From: Worker |
1 From: Worker | 8 From: Worker |
2 From: Worker | 9 From: Worker |
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: Alert | 6 From: Alert |
1 From: Alert | 7 From: Alert |
2 From: Alert | 0 From: Sleepy |
0 From: Sleepy | 1 From: Sleepy |
1 From: Sleepy | 0 From: Sleepy |
End | 1 From: Sleepy |
3 From: Alert | 0 From: Sleepy |
4 From: Alert | 1 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: Alert | 1 From: Sleepy |
1 From: Alert | End |
2 From: Alert | 0 From: Sleepy |
3 From: Alert | 1 From: Sleepy |
4 From: Alert | 0 From: Sleepy |
5 From: Alert | 1 From: Sleepy |
6 From: Alert | 0 From: Sleepy |
7 From: Alert | 1 From: Sleepy |
0 From: Sleepy | |