Distributed and Parallel Processing George Wells
Threads in Java Simplified lifecycle New Runnable Running Dea d Blocked Blocking event Unblocked Scheduler run() completes start() Thread scheduling is preemptive, but not necessarily time-sliced – Use Thread.sleep(x) or Thread.yield()
Thread Control Various methods: – isAlive() – getpriority() and setpriority(x) – join() – Thread.currentThread()
Exercise Write a class ( MyThread ) – Implements Runnable – run() consists of a loop (10x) printing the thread's name and sleeping for 1s Write a main program that creates 3 of these threads and runs them – Use join() to wait for them – Experiment with the setName method – Experiment with changing priorities and see what the effects are
Synchronisation Seen the effects of lack of synchronisation – Mandelbrot example Solution: – Use synchronized modifier on method Synchronized methods/blocks obtain a lock on the object before proceeding – No other thread can execute synchronised code on that object while the lock is held – Mutual exclusion (mutex) More to it than that!
Example: Producer-Consumer Specialised instance of the pipeline pattern – One process/thread produces data – Another uses (consumes) this data Uses some form of “communication channel” – We assume a simple queue
public class ArrayQueue { private T[] data; private int hd, tl; public ArrayQueue () { data = (T[])new Object[10]; hd = tl = -1; } // Constructor public void add (T item) { tl = (tl + 1) % data.length; data[tl] = item; if (hd == -1) // First item in queue hd = tl; } // add public T remove () { int tmpIndex = hd; if (hd == tl) // Was last element hd = tl = -1; else hd = (hd + 1) % data.length; return data[tmpIndex]; } // remove } // class ArrayQueue Queue Class
Main Program Producer class – Generates stream of random numbers – Places numbers in queue Consumer class – Retrieves numbers from queue – Displays square
Problem! No synchronisation But we need more than just synchronized methods – Need to handle queue empty/full conditions wait() – Relinquishes lock, and waits for notification notify() and notifyAll() – Release one/all waiting threads – It/they must wait to reacquire the lock
Queue Class The add method: public synchronized void add (T item) { while (((tl + 1) % data.length) == hd) wait(); // No space tl = (tl + 1) % data.length; data[tl] = item; if (hd == -1) // First item in queue hd = tl; notifyAll(); // Release any consumers } // add A little more complicated – wait() may throw InterruptedException
Queue Class The remove method: public synchronized T remove () { while (hd == -1) // No data wait(); int tmpIndex = hd; if (hd == tl) // Was last element hd = tl = -1; else hd = (hd + 1) % data.length; notifyAll(); // Release waiting producers return data[tmpIndex]; } // remove
Exercise Experiment with slowing either the producer or the consumer down – Use Thread.sleep() Experiment with multiple producers and/or consumers
Threads in Java Full lifecycle New Runnable Running Dea d Blocked Blocking event Unblocked Scheduler run() completes start() Blocked in lock pool Blocked in wait pool synchronized wait() notify() or interrupt() Acquires lock
Deadlock Major problem in parallel systems Thread 1 obtains lock on object A Attempts to obtain lock on object B Thread 2 obtains lock on object B Attempts to obtain lock on object A Hard to detect and prevent – Enforce rigid ordering of obtaining multiple locks – suspend, resume and stop methods deprecated