Client-Server Programming
Spring Semester, 2005 Threads part 2 |
||
---|---|---|
© 2005, All Rights Reserved, SDSU & Roger Whitney San Diego State University -- This page last updated 23-Feb-05 |
wait and notify Methods in Object
Passing Data – Multiple Thread Access
Copyright ©, All rights reserved.2005 SDSU & Roger Whitney, 5500 Campanile Drive, San Diego, CA 92182-7700 USA. OpenContent ( http://www.opencontent.org/opl.shtml) license defines the copyright on this document.
CS 580 Spring 05 | Doc 10, Threads part 2 Slide # 2 |
Cancellable Activities, Doug Lea, October 1998, http://gee.cs.oswego.edu/dl/cpj/cancel.html
Concurrent Programming in Java: Design Principles and Patterns , Doug Lea, Addison-Wesley, 1997
The Java Programming Language , 2 nd Ed. Arnold & Gosling, Addison-Wesley, 1998
Java's Atomic Assignment, Art Jolin, Java Report , August 1998, pp 27-36.
Java 1.4.2 on-line documentation http://java.sun.com/j2se/1.4.2/docs/api/overview-summary.html
Java Network Programming 2nd Ed., Harold, O'Reilly, Chapter 5
Java Network Programming, 3nd Ed., Harold, Chapter 5. (Java)
CS 580 Spring 05 | Doc 10, Threads part 2 Slide # 3 |
Sent to a thread to interrupt it
A thread has interrupted status flag
InterruptedException is thrown if thread is blocked a call to:
and the interrupted status flag is cleared
ClosedByInterruptException is thrown if the thread is blocked
and the interrupted status flag is set
Interruptible channels are part of JDK 1.4 NIO package
If the thread is blocked by a selector:
If none of the other conditions hold then the thread’s interrupt status is set
CS 580 Spring 05 | Doc 10, Threads part 2 Slide # 4 |
If a thread is blocked on a read/write to a:
The interrupt does not interrupt the read/write operation!
The threads interrupt flag is set
Until the IO is complete the interrupt has no effect
This is one motivation for the NIO package
CS 580 Spring 05 | Doc 10, Threads part 2 Slide # 5 |
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"); } }
From: Thread-0 (repeated many times) End of main From: Thread-0 (repeated until program is killed)
CS 580 Spring 05 | Doc 10, Threads part 2 Slide # 6 |
This example uses the test Thread.interrupted() to allow the thread to be continue execution later.
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(); } }
From: Thread-0 Clean up operations From: Thread-0 From: Thread-0 (repeated)
CS 580 Spring 05 | Doc 10, Threads part 2 Slide # 7 |
Interrupt and sleep, join & wait
Let thread A be in the not runnable state due to being sent either the sleep(), join() or wait() methods. Then if thread A is sent the interrupt() method, it is moved to the runnable state and InterruptedException is raised in thread A. In the example below, NiceThread puts itself to sleep. While asleep it is sent the interrupt() method. The code then executes the catch block.
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(); } }
Thread started From: Thread-0 From: Thread-0 In catch
CS 580 Spring 05 | Doc 10, Threads part 2 Slide # 8 |
Since main sends the sleep method, not the thread itself, the InterruptedException is not thrown.
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" ); } } }
Thread started From: Thread-0 From: Thread-0 Clean up operations
CS 580 Spring 05 | Doc 10, Threads part 2 Slide # 9 |
A method is executed in the thread that sends the method
missManners.sleep( 50);
Put the current thread to sleep not the missManners thread
CS 580 Spring 05 | Doc 10, Threads part 2 Slide # 10 |
With multiprocessing we need to address mutual access by different threads. When two or more threads simultaneously access the same data there may be problems. Some types of access are safe. If a method accesses just local data, then multiple threads can safely call the method on the same object. Assignment statements of all types, except long and double, are atomic. That is a thread can not be interrupted by another thread while performing an atomic operation.
CS 580 Spring 05 | Doc 10, Threads part 2 Slide # 11 |
Synchronize is Java's mechanism to insure that only one thread at a time will access a piece of code. We can synchronize methods and block's of code (synchronize statements).
When a thread executes a synchronized instance method on an object, that object is locked. The object is locked until the method ends. No other thread can execute any synchronized instance method on that object until the lock is released. The thread that has the lock can execute multiple synchronized methods on the same object. The synchronization is on a per object bases. If you have two objects, then different threads can simultaneously execute synchronized methods on different objects. Unsynchronized methods can be executed on a locked object by any thread at any time. The JVM insures that only one thread can obtain a lock on an object at a time.
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 ); } }
CS 580 Spring 05 | Doc 10, Threads part 2 Slide # 12 |
A synchronized static method creates a lock on the class, not the object. When one thread has a lock on the class, no other thread can execute any synchronized static method of that class. Other threads can execute synchronized instance methods on objects of that class.
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 ); } }
CS 580 Spring 05 | Doc 10, Threads part 2 Slide # 13 |
A block of code can be synchronized. The basic syntax is:
synchronized ( expr ) { statements }
The expr must evaluate to an object. This will lock the object. The lock is released when the thread finishes the block. Until the lock is released, no other thread can enter any method or synchronized block that is locked by the given object.
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"); } } }
CS 580 Spring 05 | Doc 10, Threads part 2 Slide # 14 |
This example shows that a lock on an object also locks all access to the object via synchronized methods.
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"); } }
In Block
Start run
Before sleep
End Block
In enter
End run
(why does this come at the end?)CS 580 Spring 05 | Doc 10, Threads part 2 Slide # 15 |
If you want a method in a subclass to be synchronized you must declare it to be synchronized.
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 }
CS 580 Spring 05 | Doc 10, Threads part 2 Slide # 16 |
wait and notify are some of the most useful thread operations.
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.
CS 580 Spring 05 | Doc 10, Threads part 2 Slide # 17 |
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 }
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
CS 580 Spring 05 | Doc 10, Threads part 2 Slide # 18 |
synchronized void changeMethod() { Change some value used in a condition test notify(); }
CS 580 Spring 05 | Doc 10, Threads part 2 Slide # 19 |
Over the next five slides is a typical consumer-producer example. Producers "make" items, which they put into a queue. Consumers remove items from the queue. What happens when the consumer wishes to remove when the queue is empty? Using threads, we can have the consumer thread wait until a producer thread adds items to the queue.
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); } }
CS 580 Spring 05 | Doc 10, Threads part 2 Slide # 20 |
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; } } }
CS 580 Spring 05 | Doc 10, Threads part 2 Slide # 21 |
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; } } }
CS 580 Spring 05 | Doc 10, Threads part 2 Slide # 22 |
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(); } }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
CS 580 Spring 05 | Doc 10, Threads part 2 Slide # 23 |
An object is passed between threads
If multiple threads have a reference to the same object
When one thread changes the object the change is global
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
CS 580 Spring 05 | Doc 10, Threads part 2 Slide # 24 |
Returning data
pubic foo getFoo() { return foo.clone(); }
Parameters
anObject.doSomeMunging( bar.clone());
anObject doSomeMunging: bar copy
CS 580 Spring 05 | Doc 10, Threads part 2 Slide # 25 |
Pass objects that cannot change
Java’s base type and Strings are immutable
CS 580 Spring 05 | Doc 10, Threads part 2 Slide # 26 |
Perform some operation in the background
At same time perform some operations in the foreground
Need to get the result when operation is done
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(); } }
CS 580 Spring 05 | Doc 10, Threads part 2 Slide # 27 |
A future starts a computation in a thread When you need the result ask the future You will block if the result is not ready
Promise class in VisualWorks
| delayedAnswer realAnswer | delayedAnswer := [aClient perform: ‘computePi’ ] promise. Do some other work here realAnswer := delayedAnswer value
CS 580 Spring 05 | Doc 10, Threads part 2 Slide # 28 |
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(); } }
CS 580 Spring 05 | Doc 10, Threads part 2 Slide # 29 |
Have the background thread call a method when it is done
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 ); } } }
Copyright ©, All rights reserved.
2005 SDSU & Roger Whitney, 5500 Campanile Drive, San Diego, CA 92182-7700 USA.
OpenContent license defines the copyright on this document.