A race condition occurs anytime that the execution of one thread interferes with the desired behavior of another thread. What is the expected postcondition for the following bump() method? What should racehasoccurred() return? public class Shared0 { private static int x = 0, y = 0; public static void bump() throws InterruptedException { x++; Thread.currentThread().yield(); y++; public static boolean racehasoccurred() { return x!= y; This page left intentionally blank. 1
public class Race0 extends Thread { private Driver0 thedriver; public Race0(Driver0 d) { thedriver = d; public void run() { for (int i = 1; i < 1000; i++) { if (Shared0.raceHasOccurred()) System.out.print("R"); else System.out.print("."); if (i % 60 == 0) System.out.println(); Thread.currentThread().yield(); thedriver.setdonetotrue(); public class Driver0 { private boolean raceisdone = false; private Thread race0; public Driver0() { race0 = new Race0(this); race0.start(); while (!raceisdone) { Shared0.bump(); Thread.currentThread().yield(); catch (InterruptedException e) { public void setdonetotrue() { raceisdone = true; public static void main(string[] x) { new Driver0(); 2
Every Java object can be owned in one of two ways: synchronized (objectref) { // the objectref object is owned (locked) for the duration of this instruction.... synchronized returntype somemethod (parmlist) { // the this object is owned (locked) for the duration of this method call.... When a thread owns an object, any other thread attempting to gain ownership of the same object will be suspended (blocked) until the ownership is released. A instruction forms a segment of code that is mutually exclusive to all other code synchronized on the same object. synchronized methods in the same class create a monitor. wait(), notify() and notifyall() can only be called upon a owned object. (These Object methods are explained later.) Closing the earlier race condition. public class Shared1 { private static int x = 0, y = 0; public static synchronized void bump() throws InterruptedException { x++; Thread.currentThread().yield(); y++; public static synchronized boolean racehasoccurred() { return x!= y; Critical sections must be mutually exclusive in execution for correct behavior. 3
Requirements for two code segments to form critical sections with respect to each other: 1 The two segments execute concurrently. 2 The two segments share some data. 3 At least one of the segments alters the shared data. - from Object Suspend the thread, placing it in the waiting list associated with the object. (Note that the thread must have ownership prior to wait() and that ownership is relinquished by the wait().) - from Object Release one thread from the waiting list associated with the object. The released thread will attempt again to gain ownership. If the waiting list is empty, then notify() does nothing. - from Object notify() all threads in the object's waiting list. 4
threadobj = new MyThread(); New Dead return from run() threadobj.start(); threadobj.wait(); threadobj.notify(); Runnable threadobj.sleep(t); t millisec. expires Blocked threadobj.yield(); I/O completes I/O starts Often threads need to coordinate execution so that one task from some thread occurs prior to a different task in another thread. EXAMPLE (from a Three Stooges movie) Imagine three threads: MoeThread, LarryThread and CurlyThread. Each thread is responsible for executing code that does damage to the associated stooge. The proper order of damage is: 1) Moe slugs Larry. 2) Curly slaps himself. 3) Moe is punched repeatedly by another actor. 5
public class LarryThread extends Thread { public void run() { System.out.println("Larry is ready."); Shared.waitingA.synchroWait(); System.out.println("Moe slugs Larry"); Shared.waitingB.synchroNotify(); public class CurlyThread extends Thread { public void run() { System.out.println("Curly is ready."); Shared.waitingB.synchroWait(); System.out.println("Curly slaps himself."); Shared.waitingC.synchroNotify(); public class MoeThread extends Thread { public void run() { System.out.println("Moe is ready."); Shared.waitingA.synchroNotify(); Shared.waitingC.synchroWait(); System.out.println("Moe is punched by another actor."); public class Shared { public static SynchroWaiter waitinga = new SynchroWaiter(); public static SynchroWaiter waitingb = new SynchroWaiter(); public static SynchroWaiter waitingc = new SynchroWaiter();; INCORRECT SynchronizeWaiter public class SynchroWaiter { public synchronized void synchrowait() { wait(); catch (InterruptedException e) { public synchronized void synchronotify() { notify(); 6
CORRECT SynchronizeWaiter public class SynchroWaiter { private int waitcount = 0; public synchronized void synchrowait() { waitcount++; if (waitcount >= 1) wait(); catch (InterruptedException e) { public synchronized void synchronotify() { waitcount--; notify(); Producer thread monitorobj.deposit(data); Consumer thread monitorobj.remove(data); public class Monitor { private final int numberofbuffers = 100; private int buffersinuse = 0; public synchronized void deposit( Stuff data ) { while (buffersinuse == numberofbuffers) wait(); catch (InterruptedException e) { placeinnextavailablebuffer(data); buffersinuse++; notifyall(); public synchronized Stuff remove() { while (buffersinuse == 0) wait(); catch (InterruptedException e) { Stuff stuff = datafromoldestbuffer(); buffersinuse--; notifyall(); return stuff; 7
isalive() - from Thread Returns true unless the thread is dead. obj.join() - from Thread Causes the executing thread to suspend awaiting the obj thread to die. interrupt() - from Thread If the thread is blocked via wait or join, then InterruptException is thrown. If the thread is blocked for I/O, then ClosedByInterruptException is thrown. setpriority(int p) - from Thread Assigns a priority to a thread. Higher numbers mean higher priority to execute. setdaemon(boolean on) - from Thread Sets a thread as a daemon or not. Daemons can continue to run in the background when a program terminates. suspend(), resume(), stop() - from Thread All are deprecated! 8