CS 580 Client-Server Spring Semester, 2004 Threads part 2 |
||
---|---|---|
© 2004, All Rights Reserved, SDSU & Roger Whitney San Diego State University -- This page last updated 04-Mar-04 |
Source Code In Lecture
Smalltalk
Thread Control
Java interrupt()
Sent to a thread to interrupt it
A thread has interrupted status flag
JDK 1.4 Doc state
InterruptedException is thrown if thread is blocked a call to:
Interrupt and Pre JDK 1.4 NIO operations
If a thread is blocked on a read/write to a:
Interrupt does not stop a Thread
The following program does not end
The interrupt just sets the interrupt flag!
public class NoInterruptThread extends Thread { public void run() { while ( true) { System.out.println( "From: " + getName() ); } } public static void main(String args[]) throws InterruptedException{ NoInterruptThread focused = new NoInterruptThread( ); focused.setPriority( 2 ); focused.start(); Thread.currentThread().sleep( 5 ); // Let other thread run focused.interrupt(); System.out.println( "End of main"); } }Output From: Thread-0 (repeated many times) End of main From: Thread-0 (repeated until program is killed)
Using Thread.interrupted
public class RepeatableNiceThread extends Thread { public void run() { while ( true ) { while ( !Thread.interrupted() ) System.out.println( "From: " + getName() ); System.out.println( "Clean up operations" ); } } public static void main(String args[]) throws InterruptedException{ RepeatableNiceThread missManners = new RepeatableNiceThread( ); missManners.setPriority( 2 ); missManners.start(); Thread.currentThread().sleep( 5 ); missManners.interrupt(); } }Output From: Thread-0 Clean up operations From: Thread-0 From: Thread-0 (repeated)
Interrupt and sleep, join & wait
public class NiceThread extends Thread { public void run() { try { System.out.println( "Thread started"); while ( !isInterrupted() ) { sleep( 5 ); System.out.println( "From: " + getName() ); } System.out.println( "Clean up operations" ); } catch ( InterruptedException interrupted ) { System.out.println( "In catch" ); } } public static void main( String args[] ) { NiceThread missManners = new NiceThread( ); missManners.setPriority( 6 ); missManners.start(); missManners.interrupt(); } }Output Thread started From: Thread-0 From: Thread-0 In catch
Who Sends sleep() is Important
public class WhoSendsSleep 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" ); } } public static void main( String args[] ) { try { NiceThread missManners = new NiceThread( ); missManners.setPriority( 1 ); missManners.start(); missManners.sleep( 50); //Which thread is sleeping? missManners.interrupt(); } catch ( InterruptedException interrupted ) { System.out.println( "Caught napping" ); } } }Output Thread started From: Thread-0 From: Thread-0 Clean up operations
Threads & Method Sends
A method is executed in the thread that sends the method
missManners.sleep( 50);
Put the current thread to sleep not the missManners thread
Smalltalk interrupt
interruptWith: ablock
| process result | result := WriteStream on: String new. process := [1 to: 5000 do: [:each | result nextPutAll: each printString; cr. Processor activeProcess yield]] fork. (Delay forMilliseconds: 1) wait. process interruptWith: [result nextPutAll: 'Interrupt']. (Delay forMilliseconds: 100) wait. Transcript clear; show: result contents
Safety - Mutual Access
Java Safety - Synchronize
Synchronized Instance Methods
class SynchronizeExample { int[] data; public String toString() { return "array length " + data.length + " array values " + data[0]; } public synchronized void initialize( int size, int startValue){ data = new int[ size ]; for ( int index = 0; index < size; index++ ) data[ index ] = (int ) Math.sin( index * startValue ); } public void unSafeSetValue( int newValue) { for ( int index = 0; index < data.length; index++ ) data[ index ] = (int ) Math.sin( index * newValue ); } public synchronized void safeSetValue( int newValue) { for ( int index = 0; index < data.length; index++ ) data[ index ] = (int ) Math.sin( index * newValue ); } }
Synchronized Static Methods
class SynchronizeStaticExample { int[] data; static int[] classData; public synchronized void initialize( int size, int startValue){ data = new int[ size ]; for ( int index = 0; index < size; index++ ) data[ index ] = (int ) Math.sin( index * startValue ); } public synchronized void initializeStatic( int size, int startValue){ classData = new int[ size ]; for ( int index = 0; index < size; index++ ) classData[ index ] = (int ) Math.sin( index * startValue ); } }
Synchronized Statements
synchronized ( expr ) { statements }
A synchronized method is syntactic sugar for a synchronized block.
class LockTest { public synchronized void enter() { System.out.println( "In enter"); } }Is the same as:
class LockTest { public void enter() { synchronized ( this ) { System.out.println( "In enter"); } } }
Lock for Block and Method
public class LockExample extends Thread { private Lock myLock; public LockExample( Lock aLock ) { myLock = aLock; } public void run() { System.out.println( "Start run"); myLock.enter(); System.out.println( "End run"); } public static void main( String args[] ) throws Exception { Lock aLock = new Lock(); LockExample tester = new LockExample( aLock ); synchronized ( aLock ) { System.out.println( "In Block"); tester.start(); System.out.println( "Before sleep"); Thread.currentThread().sleep( 5000); System.out.println( "End Block"); } } } class Lock { public synchronized void enter() { System.out.println( "In enter"); } }Output In Block
Start run
Before sleep
End Block
In enter
End run (why does this come at the end?)
Synchronized 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 }
wait and notify Methods in Object
public final void wait(timeout) throws InterruptedException
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
notify - How to Use
synchronized void changeMethod() { Change some value used in a condition test notify(); }
wait and notify Example
import java.util.ArrayList; public class SharedQueue { ArrayList elements = new ArrayList(); public synchronized void append( Object item ) { elements.add( item); notify(); } public synchronized Object get( ) { try { while ( elements.isEmpty() ) wait(); } catch (InterruptedException threadIsDone ) { return null; } return elements.remove( 0); } }
wait and notify - Producer public class Producer extends Thread { SharedQueue factory; int workSpeed; public Producer( String name, SharedQueue 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 public class ProducerConsumerExample { public static void main( String args[] ) throws Exception { SharedQueue wallmart = new SharedQueue(); 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
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Smalltalk Saftey – Semaphore & RecursionLock
VisualWorks implements a Semaphore
Important Methods
Semaphore>>wait
lock critical: [lock critical: [Transcript cr; show: 'entered']]
Simple Semaphore Example
| lock consumer result |
lock := Semaphore new.
result := WriteStream on: String new.
consumer :=
[:name |
5 timesRepeat:
[lock wait.
result
nextPutAll: name , ' got it';
cr.
Processor activeProcess yield]].
(consumer newProcessWithArguments: #('A')) resume.
(consumer newProcessWithArguments: #('B')) resume.
[5 timesRepeat:
[result
nextPutAll: 'Produced 2';
cr.
lock
signal;
signal.
Processor activeProcess yield]]
fork.
(Delay forMilliseconds: 500) wait.
Transcript
clear;
show: result contents
Output Produced 2
A got it
B got it
Produced 2
A got it
B got it
Produced 2
A got it
B got it
(pattern occurs a total of 5 times)
Some Thread Issues & Ideas
Passing Data – Multiple Thread Access
Situation
An object is passed between threads
Issue
If multiple threads have a reference to the same object
When one thread changes the object the change is global
Example
anObject = anotherThreadObject.getFoo(); // line A System.out.println( anObject); // line B
If multiple threads have access to anObject
The state of anObject can change after line A ends and before line B starts!
This can cause debugging nightmares
Passing Data – Multiple Thread Access Possible Solutions
Pass copies
Returning data
pubic foo getFoo() { return foo.clone(); }
foo ^foo copy
Parameters
anObject.doSomeMunging( bar.clone());
anObject doSomeMunging: bar copy
Passing Data – Multiple Thread Access Possible Solutions
Immutable Objects
Pass objects that cannot change
Java’s base type and Strings are immutable
In VisualWorks 7 any object can be made immutable
Background Operations
Situation
Perform some operation in the background
At same time perform some operations in the foreground
Need to get the result when operation is done
Issue
Don’t make the code sequential
Avoid polling
public class Poll { public static void main( String args[] ) { TimeConsumingOperation background = new TimeConsumingOperation(); background.start(); while ( !background.isDone() ) { performSomethingElse; } Object neededInfo = background.getResult(); } }
Futures
Smalltalk
Promise class in VisualWorks
| delayedAnswer realAnswer | delayedAnswer := [aClient perform: ‘computePi’ ] promise. Do some other work here realAnswer := delayedAnswer value
Sample Java Future
class FutureWrapper { TimeConsumingOperation myOperation; public FutureWrapper() { myOperation = new TimeConsumingOperation(); myOperation.start(); } public Object value() { try { myOperation.join(); return myOperation.getResult(); } catch (InterruptedException trouble ) { DoWhatIsCorrectForYourApplication; } } }
public class FutureExample { public static void main( String args[] ) { FutureWrapper myWorker = new FutureWrapper(); DoSomeStuff; DoMoreStuff; x = myWorker.value(); } }
Callbacks
Have the background thread call a method when it is done
Java Outline class MasterThread { public void normalCallback( Object result ) { processResult; } public void someMethod() { compute; TimeConsumingOperation backGround = new TimeConsumingOperation( this ); backGround.start(); moreComputation; } } class TimeConsumingOperation extends Thread { MasterThread master; public TimeConsumingOperation( MasterThread aMaster ) { master = aMaster; } public void run() { DownLoadSomeData; PerformSomeComplexStuff; master.normalCallback( resultOfMyWork ); } } }
Smalltalk Outline
ClientCode>>startBackground [| result | result := anObject performSomeCalculation. self processResult: result] fork
ClientCode>>processResult: aResult Handle the result here
ClientCode>>aMethod Do some work self startBackground. Do more work
Copyright ©, All rights reserved.
2004 SDSU & Roger Whitney, 5500 Campanile Drive, San Diego, CA 92182-7700 USA.
OpenContent license defines the copyright on this document.
Previous    visitors since 04-Mar-04    Next