220 likes | 229 Views
G53SRP: Java Concurrency Control (2) – wait/notify. Chris Greenhalgh School of Computer Science. Contents. Wait/notify overview Wait() Notify() Infinite buffer General concurrency control Reader/writer lock Timed wait Summary Book: Wellings 3.2. Wait queue. wait. notify.
E N D
G53SRP: Java Concurrency Control (2) – wait/notify Chris Greenhalgh School of Computer Science
Contents • Wait/notify overview • Wait() • Notify() • Infinite buffer • General concurrency control • Reader/writer lock • Timed wait • Summary • Book: Wellings 3.2
Wait queue wait notify Wait/notify Overview Object • Every Java object has a wait queue as well as a lock • Only a thread holding the lock can manipulate the wait queue • The queue is manipulated using the java.lang.Object methods wait(…) and notify()/ notifyAll()… • All classes extend java.lang.Object Lock Method…
wait() • A thread calling wait is added to the wait queue • (not necessarily the end) • It releases the object lock while waiting • It re-obtains the object lock before returning • Why use wait? • Efficient task cooperation (avoids polling and avoids race conditions or lock-out with sleep)
Gains lock on ‘this’ has lock Releases lock on ‘this’ has lock Releases lock on ‘this’ Wait detail Thread • …synchronized (this) { try { this.wait(); } catch (InterruptedException ie) { }} Added to wait queue (time passes) Woken from wait queue (time passes) Re-gains lock on ‘this’
notify() • A thread calling notify() wakes one thread(s) from the wait queue • A thread calling notifyAll() wakes all thread(s) from the wait queue • If there are no threads waiting then the calls have no effect • Notifies are not “queued” or “persistent” • Waiting threads are not subdivided or classified • Notify cannot wake a certain kind of thread or method • => less efficient than some alternative
Class Buffer<T> { Vector<T> data = new Vector<T>(); synchronized voidput(T item) { data.add(item); notify(); } … … public synchronized T get() { while (data.size()==0) { try { wait(); } catch(InterruptedException ie) {} } T item = data.get(0); data.remove(0); return item; } } has lock wakes has lock Infinite buffer
Infinite buffer - cases • get(), data in buffer • Removes and returns first item • get(), no data in buffer • Waits until data present • put(), no thread waiting • Add data to buffer (notify is no-op) • put(), thread(s) waiting • Add data to buffer, wake one thread
Infinite buffer - notes • notify() may wake any waiting thread • But only threads calling get ever wait • Put only adds one item • only one waiting thread can now take this item, so only needs to be woken up • wait() may terminate due to interrupt • A waiting thread may be beaten to the lock by a new get() thread • E.g. if it was already waiting to obtain the lock • So it has to be ready to wait more than once!
Thread 1 … Entry protocol Critical section Exit protocol … Entry: Block until safe to proceed (update state) Thread 2 … Entry protocol Critical section Exit protocol … Exit: (update state) Wake any blocked threads now able to proceed General concurrency control
Class Buffer<T> { Vector<T> data = new Vector<T>(); synchronized voidput(T item) { data.add(item); notify(); } … … public synchronized T get() { while (data.size==0) { try { wait(); } catch(InterruptedException ie) {} } T item = data.get(0); data.remove(0); return item; } } entry Critical section exit Infinite buffer revisited
Infinite buffer notes • Object lock is held during critical section • So at most one thread can be in critical section • If more than one thread should be in critical section then lock must be released and regained • E.g. separate into two synchronized blocks
This: … synchronized void method() { … } … static synchronizedvoid method() { … } Equals: … void method() { synchronized (this) { … } } … static void method() { synchronized (ThisClass.class) { … } } Synchronized method implementation
Reader/writer lock - specification • Shared lock object • In critical section can be: • Any number of reader threads OR • Only one writer thread
Could be boolean Reader/writer lock - state Class ReaderWriterLock { int writers = 0; int readers = 0; … }
Condition Reader entry protocol public synchronized void readerEntry() { while (writers>0) { try { wait(); } catch (InterruptedException ie) {} } readers++; } Update state N.B. mutual exclusion required (synchronized!)
Writer entry protocol public synchronized void writerEntry() { while (writers>0 || readers>0) { try { wait(); } catch (InterruptedException ie) {} } writers++; }
Update state Wake one thread (if a reader was running no Reader should have been waiting) Reader exit protocol public synchronized void readerExit() { readers--; if (readers==0) notify(); } Could use notifyAll() would be safer because ____________________ but_____________________________
Update state Wake all threads (there may be several readers waiting) Writer exit protocol public synchronized void writerExit() { writers--; notifyAll(); }
Reader/writer lock notes • What happens if calls to entry/exit are not matched? • Enter without exit?Deadlock, as lock never released • Exit without enter?Error or incorrect admission of concurrent threads
Timed wait() • wait() waits indefinitely • Or until interrupted • wait(long millis) waits at most millis ms before attempted to regain lock & continue • But wait(0) waits indefinitely • Cannot tell if timed out or notified! • Allows time-out • E.g. error or deadlock detection
Summary • Each object has a wait queue as well as a lock • = “monitor” • wait() blocks a thread and releases the lock until notify()/notifyAll() • Supports general concurrency control • Can be used to avoid busy waiting or polling • Additional variable(s) are required to track concurrency requirements