David Evans CS201j: Engineering Software University of Virginia Computer Science Lecture 16: Concurrent Programming
28 October 2003CS 201J Fall Menu Section Problems Concurrent Programming
28 October 2003CS 201J Fall StringSet <= StringBag ? Signature rule: subtype must implement all supertype methods –StringBag has method public int count (String s) not implemented by StringSet Signature rule is violated: StringSet is not a behavioral subtype of StringBag. Example: The statement s.count (“test”); is possible if s is a StringBag, but not if s is a StringSet.
28 October 2003CS 201J Fall StringSet <= StringBag ? Methods rule: precondition of subtype method must be weaker than precondition of supertype method StringBag: public void insert (String s) // REQUIRES: true StringSet: public void insert (String s) // REQUIRES: s is not an element of this. true s is not an element of this
28 October 2003CS 201J Fall StringBag <= StringSet Signature Rule –StringBag implements all StringSet methods –Argument types contravariant (all are same), result types covariant (all are same), no new exceptions Methods Rule –Preconditions are weaker insert: s is not an element of this true
28 October 2003CS 201J Fall StringBag <= StringSet Methods Rule: Postconditions are stronger StringBag () post StringSet () post StringBag.insert post StringSet.insert post “Adds s to this” StringBag.isIn post StringSet.isIn post “Returns true if there is at least one s in this” “Returns true if s is an element of this” StringBag.size post StringSet.size post “Returns the total number of elements in this” “Returns the number of elements in this”
28 October 2003CS 201J Fall StringBag <= StringSet Properties Rule: subtype preserves supertype properties StringSet: // OVERVIEW: StringSets are unbounded, mutable sets of Strings. StringBag: // OVERVIEW: StringBags are unbounded, // mutable bags (unordered, but the same // String may appear multiple times) of // Strings.
28 October 2003CS 201J Fall Programming Concurrency Java API: Thread –A separate execution thread –Methods Thread (Runnable r) Create a thread. The thread’s run method will invokve r.run (). start () REQUIRES: this is not already started Schedule the thread to run. The VM will start the thread and involve run ().
28 October 2003CS 201J Fall Yarn public class Yarn extends Thread { public void run () { System.err.println ("Running thread: " + currentThread ()); } public static void main (String args[]) { Yarn y = new Yarn (); y.start (); System.err.println ("Done: " + currentThread ()); } What could this produce?
28 October 2003CS 201J Fall Yarn public class Yarn extends Thread { public void run () { System.err.println ("Running thread: " + currentThread ()); } public static void main (String args[]) { Yarn y = new Yarn (); y.start (); System.err.println ("Done: " + currentThread ()); } Done: Thread[main,5,main] Running thread: Thread[Thread-0,5,main] Actual output: Running thread: Thread[Thread-0,5,main] Done: Thread[main,5,main] Plausible output:
28 October 2003CS 201J Fall Yarn public class Yarn extends Thread { public void run () { while (true) { System.err.println ("Running thread: " + currentThread ()); } public static void main (String args[]) { Yarn y = new Yarn (); y.start (); System.err.println ("Done: " + currentThread ()); } Done: Thread[main,5,main] Running thread: Thread[Thread-0,5,main]
28 October 2003CS 201J Fall class Counter { private int count; public Counter () { count = 0; } public void increment () { count++; } public void decrement () { count--; } public int getValue () { return count; } } class IncThread extends Thread { private Counter c; public IncThread (Counter p_c) { c = p_c; } public void run () { while (true) { c.increment (); System.err.println ("Running inc thread: " + currentThread () + " / Value: " + c.getValue ()); }
28 October 2003CS 201J Fall class DecThread extends Thread { private Counter c; public DecThread (Counter p_c) { c = p_c; } public void run () { while (true) { c.decrement (); System.err.println ("Running dec thread: " + currentThread () + " / Value: " + c.getValue ()); } public class Yarn { public static void main (String args[]) { Counter c = new Counter (); IncThread ithread = new IncThread (c); DecThread dthread = new DecThread (c); ithread.start (); dthread.start (); }
28 October 2003CS 201J Fall Running inc thread: Thread[Thread-0,5,main] / Value: 1 Running inc thread: Thread[Thread-0,5,main] / Value: 2 Running inc thread: Thread[Thread-0,5,main] / Value: 3 Running inc thread: Thread[Thread-0,5,main] / Value: 4 … Running inc thread: Thread[Thread-0,5,main] / Value: 61 Running inc thread: Thread[Thread-0,5,main] / Value: 62 Running dec thread: Thread[Thread-1,5,main] / Value: 61 Running inc thread: Thread[Thread-0,5,main] / Value: 62 Running dec thread: Thread[Thread-1,5,main] / Value: 61 Running inc thread: Thread[Thread-0,5,main] / Value: 62 Running dec thread: Thread[Thread-1,5,main] / Value: 61 Running dec thread: Thread[Thread-1,5,main] / Value: 60 … Running dec thread: Thread[Thread-1,5,main] / Value: 1 Running dec thread: Thread[Thread-1,5,main] / Value: 0 Running dec thread: Thread[Thread-1,5,main] / Value: -1 Running inc thread: Thread[Thread-0,5,main] / Value: -1 Running inc thread: Thread[Thread-0,5,main] / Value: 0 Running inc thread: Thread[Thread-0,5,main] / Value: 1 Running inc thread: Thread[Thread-0,5,main] / Value: 2 …
28 October 2003CS 201J Fall Any race conditions? class IncThread extends Thread { private Counter c; public IncThread (Counter p_c) { c = p_c; } public void run () { while (true) { c.increment (); System.err.println ("Running inc thread: " + currentThread () + " / Value: " + c.getValue ()); }
28 October 2003CS 201J Fall public void run () { while (true) { synchronized (c) { c.increment (); System.err.println ("Running inc thread: " + currentThread () + " / Value: " + c.getValue ()); } public void run () { synchronized (c) { while (true) { c.increment (); System.err.println ("Running inc thread: " + currentThread () + " / Value: " + c.getValue ()); } Option 1 Option 2 Would hold the lock on c forever!
28 October 2003CS 201J Fall Banking How can we ensure that the counter value never goes negative?
28 October 2003CS 201J Fall Priorities In general, threads with higher priorities will be scheduled preferentially. There are no guarantees Thread void setPriority (int newPriority) // MODIFIES: this // EFFECTS: Changes the priority of this // thread to newPriority.
28 October 2003CS 201J Fall Priorities, Priorities ithread.setPriority (Thread.NORM_PRIORITY); ithread.start (); dthread.setPriority (Thread.MIN_PRIORITY); dthread.start (); The ithread should run more than the dthread, but there is no guarantee.
28 October 2003CS 201J Fall wait and notify Thread A synchronized (o) o.wait () Thread B synchronized (o) { o.notify () } // end synchronized can reclaim o lock
28 October 2003CS 201J Fall public class Object { public final void wait () throws InterruptedException // REQUIRES: Current thread holds the // lock for this. // EFFECTS: Causes the current thread // to release the lock and wait until // notify is called on this. If the thread // is interrupted throws InterruptedException public final void notify () // EFFECTS: If any threads are waiting on this // object, chooses one of those threads to // awaken. final means subtypes may not override this method
28 October 2003CS 201J Fall class IncThread extends Thread { private Counter c; public IncThread (Counter p_c) { c = p_c; } public void run () { while (true) { synchronized (c) { c.increment (); System.err.println ("Running inc thread: " + currentThread () + …); c.notify (); } } } } class DecThread extends Thread { … public void run () { while (true) { synchronized (c) { if (c.getValue () <= 0) { try { c.wait (); } catch (InterruptedException e) { ; } } c.decrement (); System.err.println ("Running dec thread: " + …); } } } }
28 October 2003CS 201J Fall Counter c = new Counter (); IncThread ithread = new IncThread (c); DecThread dthread = new DecThread (c); ithread.setPriority (Thread.NORM_PRIORITY); ithread.start (); dthread.setPriority (Thread.MAX_PRIORITY); dthread.start (); Running inc thread: Thread[Thread-0,5,main] / Value: 1 Running dec thread: Thread[Thread-1,10,main] / Value: 0 Running inc thread: Thread[Thread-0,5,main] / Value: 1 Running dec thread: Thread[Thread-1,10,main] / Value: 0 Running inc thread: Thread[Thread-0,5,main] / Value: 1 Running dec thread: Thread[Thread-1,10,main] / Value: 0 Running inc thread: Thread[Thread-0,5,main] / Value: 1 Running dec thread: Thread[Thread-1,10,main] / Value: 0
28 October 2003CS 201J Fall Charge Thread work = new Thread (ps5); work.setPriority (Thread.MAX_PRIORITY); work.start ();