|
CS 696 Emerging Technologies: Distributed Objects |
|
---|
Spring Semester, 1998
Java Threads
To Lecture Notes Index
© 1998, All Rights Reserved, SDSU & Roger Whitney
San Diego State University -- This page last updated 21-Apr-98
Contents of Doc 14, Java Threads
- References
- Threads
- Creating Threads
- Thread Scheduling
- Preemptive
- Single Processor -Time-slicing or not time-sliced
- Native Threads and Parallelism
- Simple Yield Example
- Sleep Example
- Suspend, Resume and Stop
- Suspend and Resume
- Join - Waiting for Thread to end
- Synchronize
- DeadLock
- Synchonized and Inheritance
- wait and notify
- wait - How to use
- notify - How to Use
- The End of an Application
- Types of Threads: user and daemon
The Java Programming Language, Arnold & Gosling, Addision-Wesley, 1996
Java 1.2b2 on-line documentation
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: 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
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
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- Rohan Native Threads
End
0 From: Thread-3
0 From: Thread-2
1 From: Thread-3
2 From: Thread-3
1 From: Thread-2
3 From: Thread-3
2 From: Thread-2
4 From: Thread-3
3 From: Thread-2
4 From: Thread-2
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
On Single Processor | On Multiple Processor Rohan |
0 From: Thread-5 | End |
1 From: Thread-5 | 0 From: Thread-3 |
2 From: Thread-5 | 1 From: Thread-3 |
3 From: Thread-5 | 2 From: Thread-3 |
4 From: Thread-5 | 0 From: Thread-2 |
0 From: Thread-4 | 3 From: Thread-3 |
1 From: Thread-4 | 1 From: Thread-2 |
2 From: Thread-4 | 2 From: Thread-2 |
3 From: Thread-4 | 4 From: Thread-3 |
4 From: Thread-4 | 3 From: Thread-2 |
End | 4 From: Thread-2 |
Thread Scheduling
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 running green-threads 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
Starting with Solaris 2.6 (or Solaris 2.5 with proper patches) java supports
the use of native Solaris threads
On multiprocessor machines native Solaris threads may be scheduled on different
processors - depends on load of each processor
The default is for java to use green-threads
To use native threads use:
java -native className
The
default version of java on rohan (1.1.3) is set up to run native threads
only
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 & Parallelism
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
A group of "From: Thread-5" will be followed by a group of "From: Thread-4" etc.
Output if not Time-sliced, Single Processor
"From: Thread-4" will repeat "forever"
Multiple Processor
"From: Thread-5" and "From: Thread-4" will intermix "forever"
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
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 ) {}
}
}
}
// 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 | |
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;}
}
}
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
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
These methods are deprecated in JDK 1.2 because they are not thread safe
Start avoiding these methods now!
Ending Thread Execution
A thread ends when its run method returns
Forcing a Thread to Quit
The Preferred Way
Running thread checks to see if it is time to stop
class Test {
public static void main( String args[] ) throws Exception{
NiceThread missManners = new NiceThread( );
missManners.setPriority( 2 );
missManners.start();
Thread.currentThread().sleep( 5 );
missManners.pleaseStop();
}
}
class NiceThread extends Thread {
protected boolean stopRequested = false;
public void pleaseStop() { stopRequested = true; }
public void run() {
while (!stopRequested)
System.out.println( "From: " + getName() );
System.out.println( "The End" );
}
}
Output
From: Thread-2
From: Thread-2
From: Thread-2
From: Thread-2
From: Thread-2
The End
What if the Thread is waiting?
If a thread is waiting for other event it will not respond to the pleaseStop
method until after the event
If the other event never happens or occurs after a long time, then the
pleaseStop is not useful
In these cases use interrupt
class Test {
public static void main( String args[] ) throws Exception{
OccupiedThread missManners = new OccupiedThread ( );
missManners.setPriority( 2 );
missManners.start();
Thread.currentThread().sleep( 5 );
missManners.interrupt();
}
}
class OccupiedThread extends Thread {
protected boolean stopRequested = false;
public void pleaseStop() { stopRequested = true; }
public void run() {
try {
while (!stopRequested) {
read();
System.out.println( "From: " + getName() );
}
System.out.println( "The End" );
}
catch (InterruptedException threadInterrupted) {
System.out.println( "Good bye" );
}
catch (IllegalMonitorStateException threadInterrupted) {
System.out.println( "Dear me" );
}
}
public void read() throws InterruptedException {
System.out.println( "In read" );
wait();
}
}
Trouble In thread Land
class Test {
public static void main( String args[] ) throws Exception{
TroubleThread missManners = new TroubleThread( );
missManners.setPriority( 2 );
missManners.start();
Thread.currentThread().sleep( 5 );
missManners.interrupt(); //Does not work
}
}
class TroubleThread extends Thread {
protected boolean stopRequested = false;
public void pleaseStop() { stopRequested = true; }
public void run() {
try{
while (!stopRequested) {
read();
}
}
catch (InterruptedException threadInterrupted){
System.out.println( "Good bye" );
}
catch (IllegalMonitorStateException threadInterrupted) {
System.out.println( "Dear me" );
}
}
public void read() throws InterruptedException {
try{
System.out.println( "In read" );
int input = System.in.read(); //Don't type anything
}
catch (IOException readError){}
}
}
Forcing a Thread to QuitStop
DO NOT USE THIS METHOD
class Test {
public static void main( String args[] ) throws Exception{
TroubleThread missManners = new TroubleThread( );
missManners.setPriority( 2 );
missManners.start();
Thread.currentThread().sleep( 5 );
missManners.stop(); //This works
}
}
Forcing a Thread to Quit
The Rambo Way
destroy
destroy method was never implemented and will not be.
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 | |
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 | |
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 here
}
// More non-critical code can go here
}
public SynchronizedClass( )
{
// Some non-critical code can go here
synchronized ( getClass() )
{
// put critical code here
}
// 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 ) );
}
}
public void unprotected()
{ System.out.println( "From unprotected" ); }
}
class Cheat extends Loop {
SyncLoop myReference;
public Cheat( SyncLoop aReference ) {
myReference = aReference;
}
public void doLoop( int size, String name ) {
for ( int count = 0; count < size; count++)
myReference.unprotected();
}
}
// 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 | |
// Synchronized Example Continued
class TestUnsynchedMethod
{
public static void main( String[] args ) throws Exception
{
SyncLoop safe = new SyncLoop();
Cheat ohNo = new Cheat( safe);
SimpleThread alert;
SleepyThread sleepy;
alert = new SimpleThread( "Alert", 16, safe );
sleepy = new SleepyThread( "Sleepy", 2, ohNo );
sleepy.setPriority( 8 );
alert.start();
sleepy.start();
System.out.println( "End" );
}
}
Output
End | 7 From: Alert |
From unprotected | 8 From: Alert |
From unprotected | 9 From: Alert |
0 From: Alert | 10 From: Alert |
From unprotected | 11 From: Alert |
From unprotected | From unprotected |
1 From: Alert | From unprotected |
2 From: Alert | 12 From: Alert |
3 From: Alert | 13 From: Alert |
4 From: Alert | 14 From: Alert |
5 From: Alert | 15 From: Alert |
6 From: Alert | 16 From: Alert |
class Friendly extends Thread {
private Friendly aFriend;
public Friendly( String name ) { super( name ); }
public void setFriend( Friendly myFriend )
{ aFriend = myFriend;}
public synchronized void hug() {
try {
System.out.println( "I " + getName() + " am hugged ");
sleep( 5 );
aFriend.rehug();
} catch ( InterruptedException notInThisExample ){}
}
public synchronized void rehug() {
System.out.println( "I " + getName() + " am rehugged ");
}
public void run() {aFriend.hug(); }
}
public class Test {
public static void main( String args[] ) {
Friendly fred = new Friendly("Fred");
Friendly sam = new Friendly( "Sam");
fred.setFriend( sam );
sam.setFriend( fred );
fred.start();
sam.start();
System.out.println( "End" );
}
}
Output
End
I Fred am hugged
I Sam am hugged
Deadlock Avoided
class Friendly extends Thread {
private Friendly aFriend;
private Object lock;
public Friendly( String name, Object lock ) {
super( name );
this.lock = lock;
}
public void setFriend( Friendly myFriend ) {
aFriend = myFriend;
}
public synchronized void hug() {
try {
System.out.println( "I " + getName() + " am hugged ");
sleep( 5 );
aFriend.rehug();
}
catch ( InterruptedException notInThisExample ) {}
}
public synchronized void rehug() {
System.out.println( "I " + getName() + " am rehugged ");
}
public void run() {
synchronized ( lock) {
aFriend.hug();
}
}
}
//Deadlock Avoided Continued
public class Test
{
public static void main( String args[] ) //throws Exception
{
Object aLock = "Schalage";
Friendly fred = new Friendly("Fred", aLock);
Friendly sam = new Friendly( "Sam", aLock);
fred.setFriend( sam );
sam.setFriend( fred );
fred.start();
sam.start();
System.out.println( "End" );
}
}
Output
End
I Sam am hugged
I Fred am rehugged
I Fred am hugged
I Sam am rehugged
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.
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.
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;
}
}
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;
}
}
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;
}
}
}
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;
}
}
}
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 0 | Sue got Nike3 | Honda produced 3 |
Honda produced 0 | Nike produced 4 | Bob got Honda3 |
Sue got Nike0 | Sue got Nike4 | Nike produced 8 |
Bob got Honda0 | Honda produced | Sue got Nike8 |
Nike produced 1 | Bob got Honda2 | Nike produced 9 |
Sam got Nike1 | Nike produced 5 | Sue got Nike9 |
Nike produced 2 | Sue got Nike5 | Honda produced 4 |
Sue got Nike2 | Nike produced 6 | Bob got Honda4 |
Honda produced 1 | Sam got Nike6 | Nike produced 10 |
Bob got Honda1 | Nike produced 7 | Sue got Nike10 |
Nike produced 3 | Sue got Nike7 | Nike produced 11 |
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
synchronized void changeMethod()
{
Change some value used in a condition test
notify();
}
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.
When an program creates threads, what happens when the main ends before the
other threads?
A program ends when the last user thread is finished
All daemon threads running when the program ends are stopped
Daemon example
class Test
{
public static void main( String args[] ) throws Exception{
InfinityThread shortLived = new InfinityThread( );
shortLived.setDaemon( true );
shortLived.start();
Thread.currentThread().sleep( 10 );
System.out.println( "Bye");
}
}
class InfinityThread extends Thread
{
public void run()
{
while (true)
{
System.out.println( "From: " + getName() );
System.out.flush();
yield();
}
}
}
Output
From: Thread-4
From: Thread-4
From: Thread-4
From: Thread-4
From: Thread-4
From: Thread-4
From: Thread-4
From: Thread-4
From: Thread-4
Bye
Debugging Threads
Some useful methods in Thread for debugging
public static void dumpStack()
- Prints a stack trace for the current thread on System.out
public String toString()
- Returns a String representation of the Thread, including the thread's name,
priority and thread group.
public int countStackFrames()
- Returns the number of stack frames in this Thread. The Thread must be
suspended when this method is called.
visitors since 24-Feb-98