Table of Contents

~~SLIDESHOW~~

Multiple Threads

Sometimes you need more than multiple objects; you need multiple subtasks. The Java Virtual Machine supports multi-threading – independent subtasks in the program’s address space.

The slides and notes in this presentation are adapted either from Thinking in Java or Groovy in Action (see Recommended Reading).

An index to the source code for all the examples in this lecture is available.

The Thread

Basic threads

Class SimpleThread

"thread".

The class diagram.

Example 1: simpleThread.groovy creates five threads, each with a unique id. run() method counts down from 5 to 0.


1|Example 1: SimpleThread (at-m42/Examples/lecture09/simpleThread.groovy)
extern> http://www.cpjobling.org.uk/~eechris/at-m42/Examples/lecture09/simpleThread.groovy

Class SimpleThread (at run time)

"thread".

The thread execution (activity diagram).


Typical Run

#1: 5		
#1: 4		
#1: 3		
#1: 2		
#1: 1		
#2: 5		
#2: 4		
#2: 3		
 ...  
#5: 2
#5: 1

Yielding control

A Yielding Thread

Yield!

public class YieldingThread extends Thread {
  // ...
  void run() {
    while(true) {
      println this
      if (--countDown == 0) {
          return
      }
      yield()
    }
  }
  // ...
}

Example 2: yieldingThread.groovy.

Typical Run

<html> <table><tr><td><pre> #1: 5 #2: 5 #4: 5 #5: 5 #3: 5 #1: 5 #5: 4 #3: 4 #1: 4 #4: 4 #5: 3 #3: 3 #1: 3 #4: 3 </pre> </td><td> <pre> #5: 2 #3: 2 #1: 2 #4: 2 #5: 1 #3: 1 #1: 1 #4: 1 #2: 4 #2: 3 #2: 2 #2: 1 </pre> </td> </tr> </table> </html>

A Sleeping Thread

Sleeping!

public class SleepingThread extends Thread {
  // ...
  void run() {
    while(true) {
       println this
      if (--countDown == 0) {
      	return
      }
      try {
        sleep(100) // 100 ms      
      } catch (InterruptedException e) {
        throw new RuntimeException(e)
      }
    }
  }
  // ...
}

Example 3: sleepingThread.groovy.


Method sleep(100) schedules a time delay of 100 ms. The Thread is suspended until this time is up. Call to sleep() must be put in a try block because it could be interrupted before it times out. You should use wait() rather than sleep() if you expect the interrupt!

Priority

Daemon Threads

Joining a Thread

Coding Variations

Runnable in Groovy

def t = new Thread () {/* closure body */}
t.start()
Thread.start{/* closure body */}

More Threads with closures

Thread.startDaemon() {/* closure body */}
new Timer().runAfter(1000) {/* closure body */}

Producer consumer

Example 4: using threads with synchronization for the producer/consumer problem.


The producer pushes integers on a stack, consumer pops items when available. The push/pop actions are reported. Actual sequence is not predictable. We use closures to run something (producing and consuming) and sleep to slow down the consumer. We introduce a Storage class that holds the stack and synchronizes access to it. If we try to pop from an empty stack, we will wait until the producer has caught up.

1|Example 4: using threads with synchronization for the producer/consumer problem (at-m42/Examples/lecture09/producerConsumer.groovy)
extern> http://www.cpjobling.org.uk/~eechris/at-m42/Examples/lecture09/producerConsumer.groovy

An unresponsive user interface

Unresponsive UI

Example 5: a responsive user interface.


1|Example 5: a responsive user interface (at-m42/Examples/lecture09/responsiveUI.groovy)
extern> http://www.cpjobling.org.uk/~eechris/at-m42/Examples/lecture09/responsiveUI.groovy

Explanation: this program simulates a problem often encountered with distributed programs, and programs that have a graphical user interface. In the first class, the while loop simulates some long running process that the user interface may have launched. Unfortunately, it never terminates, so the input statement at line 10 is never executes: in other words, the user interface has become unresponsive.

In the second example, the class is made into a daemon and the long running process is coded in the run method. This time the user interface is in a separate thread (and after 300 ms) input can be accepted from the user (which in this case allows the current version of d to be printed).

In interactive programs, the placing of long-running computation (e.g. processing of some distributed process across a network) into a separate thread, is a commonly used technique.

Sharing Limited Resources

Sharing an Object

The Bank Account

A piggy bank

l|A bank account (at-m42/Examples/lecture09/BankAccount.groovy)
extern> http://www.cpjobling.org.uk/~eechris/at-m42/Examples/lecture09/BankAccount.groovy

The Demo

Example 6 Making a deposit

if (account.balance >= amount) {
  try {
       Thread.sleep(500);  
  }  catch (InterruptedException ex)  {  
     ex.printStackTrace();
  }

l| Shared resource problems (at-m42/Examples/lecture09/ryanAndMonicaJob.groovy)
extern> http://www.cpjobling.org.uk/~eechris/at-m42/Examples/lecture09/ryanAndMonicaJob.groovy

Results


Monica's check was invalid because Ryan was already making a withdrawal. We need a way to prevent Monica starting a withdrawal if Ryan is already making a withdrawal.

Need a Lock!

<html> <table> <tr> <td> <ul> <li class=“level1”>Associate a lock with withdraw method.</li> <li class=“level1”>If Ryan or Monica wants to make a withdrawal, he/she must acquire the lock, and keep the key.</li> <li class=“level1”>If Ryan has the key, only he can access the bank account.</li> <li class=“level1”>Lock prevents Monica accessing the bank account.</li> </ul> </td> <td> <ul> <li class=“level1”>When Ryan has finished the transaction, he unlocks the object and the key becomes available.</li> <li class=“level1”>Monica can now take the key and lock the bank account to prevent Ryan making a withdrawal.</li> <li class=“level1”>Lock ensures that only one Thread has access to shared object at a time.</li> </ul> </td> </tr> </table> </html>

a lock

Creating a Lock in Java

Example 7 Locks and threads.


l| Example 7: Using a lock to control access to a shared resource (at-m42/Examples/lecture09/ryanAndMonicaJob2.groovy)
extern> http://www.cpjobling.org.uk/~eechris/at-m42/Examples/lecture09/ryanAndMonicaJob2.groovy

Object Locks

How JVM Shares Resources

synchronized f() { /* ... */ }	
synchronized g(){ /* ... */ }

The "Lost Update" problem

def increment(){ 
  i = balance;
  balance = i + 1
}

Increment balance by adding 1 to value AT TIME IT WAS READ rather than CURRENT value.

Thread A runs for a while

Thread A

Thread B runs for a while

Thread B

—-

Scheduler now makes Thread B runnable (ready to run) rather than running. Note that this is before balance has been incremented.

Thread A Runs again

Thread A

Picking up where it left off:

Thread B runs again

Thread B

And picks up exactly where it left off:

—-

i had value 3 when Thread B was stopped. Value of 3 + 1 = 4 passed to balance. Update done by A is completely overridden. Hence “Missing Update”. A common problem in distributed systems e.g. database transactions.

Make increment atomic

synchronized void increment() {
  i = balance
  balance = i + 1
}

The assignment and increment code will run to end.

Thread A Runs for a While

Thread A has the key object is locked

Thread B is selected to run

Thread B Locked object

Thread A Runs again

Thread A Key is available

Thread B is selected to run

Thread B Key is available

Synchronizing on other resources

Blocking

Four states of a thread:

  1. New: the thread object has been created but it hasn’t been started yet so it cannot run
  2. Runnable: thread can be run, when the time-slicing mechanism has CPU cycles available
  3. Dead: normally after thread returns from its run method
  4. Blocked: the thread could be run but there’s something that prevent it. While a thread is in the blocked state the scheduler will simply skip over it and not give it any CPU time

Becoming Blocked

Deadlock

Thread deadlock

Deadlock

Thread deadlock scenario

 Deadlock 2.

Thread deadlock scenario

Thread deadlock scenario

Deadlock1

Summary


Home | Previous Lecture | Lectures | Next Lecture