SDSU CS 580 Client-Server
Spring Semester, 2004
Threads part 2
Previous    Lecture Notes Index    Next    
© 2004, All Rights Reserved, SDSU & Roger Whitney
San Diego State University -- This page last updated 04-Mar-04


References

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

VisualWorks Application Developers Guide, Cincom, Chapter 11 (Smalltalk), see docs/AppDevGuide.pdf in the VW installation


Doc 17, Threads part 2 Slide # 2
Source Code In Lecture

Smalltalk
See course Store repository package ThreadLecture1 version 1.4


Doc 17, Threads part 2 Slide # 3

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


Doc 17, Threads part 2 Slide # 4
Interrupt and Pre JDK 1.4 NIO operations

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


Doc 17, Threads part 2 Slide # 5
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)


Doc 17, Threads part 2 Slide # 6
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)


Doc 17, Threads part 2 Slide # 7

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

Doc 17, Threads part 2 Slide # 8
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


Doc 17, Threads part 2 Slide # 9
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

Doc 17, Threads part 2 Slide # 10

Smalltalk interrupt


interruptWith: ablock
Force the receiver to interrupt whatever it is doing and to evaluate aBlock
Receiver continues what ever it was doing after evaluating 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

Output

The numbers then ŒInterrupt¹ then the rest of the numbers.

Doc 17, Threads part 2 Slide # 11

Safety - Mutual Access




Doc 17, Threads part 2 Slide # 12

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

Doc 17, Threads part 2 Slide # 13

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


Doc 17, Threads part 2 Slide # 14

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

Doc 17, Threads part 2 Slide # 15
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?)


Doc 17, Threads part 2 Slide # 16

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
      }

Doc 17, Threads part 2 Slide # 17

wait and notify Methods in 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.



Doc 17, Threads part 2 Slide # 18

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

Doc 17, Threads part 2 Slide # 19

notify - How to Use

synchronized void changeMethod()
   {
   Change some value used in a condition test
   notify();
   }

Doc 17, Threads part 2 Slide # 20
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);
   }
}

Doc 17, Threads part 2 Slide # 21
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;
         }
      }
   }

Doc 17, Threads part 2 Slide # 22
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;
         }
      }
   }

Doc 17, Threads part 2 Slide # 23
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

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


Doc 17, Threads part 2 Slide # 24

Smalltalk Saftey – Semaphore & RecursionLock


VisualWorks implements a Semaphore

Important Methods

Semaphore>>wait
Causes the process to block until it is signaled

Semaphore>>signal
If processes are waiting allow the first one to proceed.
If no process is waiting, remember the excess signal.

Semaphore>>critical: aBlock
If not currently executing another critical: or wait run aBlock
Otherwise wait until other critical: ends or signal to end wait
Normally not mixed with wait & signal
Use Semaphore forMutualExclusion to create receiver for critical:


RecursionLock

Allows calls to critical: inside critical:

lock critical: [lock critical: [Transcript cr; show: 'entered']]

If lock is a Semaphore above will deadlock

If lock is a RecursionLock the above will work correctly

Doc 17, Threads part 2 Slide # 25
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


Doc 17, Threads part 2 Slide # 26
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)

Doc 17, Threads part 2 Slide # 27

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


Doc 17, Threads part 2 Slide # 28
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



Doc 17, Threads part 2 Slide # 29
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

anObject beImmutable


Doc 17, Threads part 2 Slide # 30

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

Doc 17, Threads part 2 Slide # 31

Futures


Smalltalk

Promise class in VisualWorks

| delayedAnswer realAnswer |
delayedAnswer := [aClient perform: ‘computePi’ ] promise.
Do some other work here
realAnswer := delayedAnswer value


Doc 17, Threads part 2 Slide # 32
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();
   }
}


Doc 17, Threads part 2 Slide # 33

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

Doc 17, Threads part 2 Slide # 34
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