



Study with the several resources on Docsity
Earn points by helping other students or get them with a premium plan
Prepare for your exams
Study with the several resources on Docsity
Earn points to download
Earn points by helping other students or get them with a premium plan
The implementation of a java monitor for a counting semaphore, highlighting the challenges of ensuring safety, no barging, single signals, and passed back exceptions. The document also covers various attempts to address these challenges and the importance of understanding the low-level synchronization tool that java monitors represent.
Typology: Papers
1 / 5
This page cannot be seen from the preview
Don't miss anything!




Abstract
1 Java Is Multithreaded
Permission to make digital or hard copies of all or part of this work for personal or classroom use is granted without fee provided that copies are not made or distributed tar profit or CommerCial edvan- tageend that copies bear this notice and the full citation on the first page. 70 copy otherwise, to republish, to post on Servers Or to redistribute to lists, requires prior specific permisslon and/or a fee. SIGCSE’BB 3/99 New Orleans, LA, USA 0 1999 ACM l-581 13-085~6/99/0003...$5.
2 Object Locks
... body of method 3
type method(.. .I <
... body of method -^3
3 Java Monitors
class Monitor extends... { private... // data fields: monitor state Monitor (.. .) C...) // constructor synchronized type methodic...) {
... notifyAll0; // if state altered while (! condition) try ( wait0 ; ) catch (InterruptedException e) {) ... notifyAll(); // if state altered 3 synchronized type method2 (... ) throws InterruptedException ( ... notifyAll(); // if state altered while (! condition) wait0 ; ... notifyAll0; // if state altered 3 ... 3
Some important things to note are the following.
l The thread blocked the longest on a monitor syn- chronized method call is not guaranteed to be next thread to acquire the monitor lock when the monitor lock is released.
l The thread blocked the longest in a monitor wait method call is not guaranteed to be the one re- moved from the wait set when a not if y method call is made by some other thread in the monitor [4, page 4171.
l Since the signaling discipline is signal-and-continue [l], barging is possible [3]: a thread waiting for the monitor lock to execute a monitor synchronized method might get the lock before a signaled thread reacquires the lock, even if the not if y occurred earlier than the monitor method call. Thus, in most situations a thread should recheck its wait- ing condition when signaled
while (! condition)... wait 0 ;
... notifyAll ;,
rather than unconditionally continuing after reen- tering the monitor.
if (! condition)... wait0 ;
... notify0 ;
l Each monitor object has a single nameless anony- mous condition variable. We cannot signal one of
several threads waiting on a specific condition with not if y. It is safer to use not if yAl1 to wake up all waiting threads and let them recheck their waiting conditions. However, this might be very inefficient and greatly increase overhead.
In some situations, we can use not if y in- stead of not if yAl1 and if... wait 0 instead of while... wait 0. However, it is extremely tricky as we will see!
A not if yAl1 needs to be done by a thread be- fore a wait if any state variables that might affect other thread waiting conditions were altered by the thread after entering the monitor. This also applies when a thread leaves the monitor (returns from a monitor method call).
If a thread that is blocked inside a call to sleep, join, or wait is interrupted, then these meth- ods clear the thread’s interrupt flag and throw an InterruptedException instead of returning nor- mally. Note that no exception is thrown if a thread is interrupted while blocked waiting to acquire a monitor’s lock to execute a synchronized method. In contrast, InterruptedException is thrown by wait if a thread that has been notified is inter- rupted while blocked, waiting to reacquire the mon- itor lock.
Ignoring Interrupt edExcept ion with an empty catch block is acceptable in
while (! condition) try ( wait0 ; 1 catch (InterruptedException e) ( 3
as long as we are using notifyAl instead of no- t if y. But it is not acceptable in
if (!condition) try c waito; 3 catch (InterruptedException e) ( 3
because a thread interrupted out of its wait then reenters the monitor without being notified. How- ever, it is more desirable in either case to have the containing method throw the exception back to the method’s caller so the latter knows an interrupt oc- curred, as in method2 above.
4 Sequence of Examples Suppose we want to implement a counting, semaphore with a Java monitor. Semaphores have two operations. P: If the semaphore’s value is 0 then block, else decre- ment the value. V: If one or more threads are blocked inside P then unblock one, else increment the semaphore’s value.
V will increment the value to 0 whereas it should now be 1. The fix for this is to count the wait set separately, rather than letting the semaphore value go negative. Another, more insidious problem is present: a race condition between interrupt ( ) and not if y ( ). Sup- pose several threads are blocked inside wait 0 and then one of them is notified and then interrupted before it reacquires the monitor lock. The not if y 0 gets “lost” in that one of the other waiting threads should now proceed. So we need to catch the exception when a thread is interrupted out of wait 0 and regenerate the notifyo.
4.4 Fourth Attempt
public class CountingSemaphore ( private int value = 0; private int waitcount = 0;
public CountingSemaphore(int initial) ( if (initial > 0) value = initial; )
public synchronized void P() throws InterruptedException ( if (value == 0 I I waitcount > 0) ( waitCount++; try f wait0 ; 1 catch (InterruptedException e) ( notify0 ; // regenerate throw e; 1 finally ( waitCount--; 1 3 value-- ; 3
public synchronized void V() < value++ ; if (waitcount > 0) notify0; 3 3
We have fixed the problem of a notified thread being interrupted, but we have introduced a new problem. Suppose a thread blocked inside wait 0 is interrupted before being notified. The not if y 0 it does in its catch block will move some other waiting thread, if there is one, out of the wait set into the lock (re)acquire set. When that thread gets back into the semaphore moni- tor, its P operation will complete successfully, an error. The fix is to add a notification flag so a thread can dis- tinguish between the notify0 in V and the notify in the catch block.
4.5 Fifth Attempt
public class CountingSemaphore ( private int value = 0;
private int waitcount = 0; private boolean notified = false;
public CountingSemaphore(int initial) ( if (initial > 0) value = initial; )
public synchronized void PO throws InterruptedException { if (value == 0 I I waitcount > 0) < waitCount++; try ( do ( wait(); ) while (!notified); 1 catch (InterruptedException e) C notify0 ; throw e; ) finally ( waitCount--; 1 notified = false; 3 value--; 3
public synchronized void V() ( value++ ; if (waitcount > 0) ( notified = true; notify0 ;
Suppose multiple threads are blocked inside wait 0 in P and some other thread calls V. Because several ad- ditional V calls might barge into the monitor before a notified thread reacquires the monitor lock, we must make the notification flag an integer counter to avoid “lost” notifies. 4.6 Sixth Attempt public class CountingSemaphore ( private int value = 0; private int waitcount = 0; private int notifycount = 0;
public CountingSemaphore(int initial) { if (initial > 0) value = initial; 1
public synchronized void PO throws InterruptedException ( if (value == 0 I I waitcount > 0) C waitCount++ ; try ( do C wait () ; 1 while (notifycount == 0); ) catch (InterruptedException a) ( notify0 ; throw e;
1 finally ( waitCount--; ) notifyCount--; 1 value-- ; 1
public synchronized void V() ( value++ ; if (waitcount > 0) ( not if yCount++ ; notify0 ; 1 3
Suppose multiple threads are blocked inside wait 0 in P and several calls to V barge ahead of any of the notified threads reacquiring the monitor lock. If the number of barging V calls exceeds the number of waiting threads, then a barging call to P will needlessly wait. To fix this, we change the condition that determines if a thread calls wait () inside P. Also, only as many notifies need be done as there are waiting threads; therefore, we refine the condition of the if statement in the V code. One major problem, though, remains to be fixed. Consider the following sequence of events. A thread calls P and waits because the semaphore value is 0. Then, some thread calls V. Before the notified thread reacquires the monitor lock, it is interrupted. Note that the semaphore value and the notification counter are both 1. Next, some thread calls P and it completes successfully. The semaphore value is now 0, but the notification counter remains 1. Then several threads call P and wait. Next, one of the waiting threads is in- terrupted, causing its wait call to throw an exception. Due to the catch block, the thread reenters the monitor, calls notify()) and rethrows the exception. Now, one of the remaining waiting threads reenters the monitor. Because the notification counter is 1, the thread thinks V was called and its P completes erroneously. The fix is to decrement the notification counter if it exceeds the wait set counter whenever a P is not required to call wait0. 4.7 Seventh Attempt The following Java monitor [Doug Lea, personal com- munication] implements a counting semaphore, has all of our desirable properties, and is race-condition free with respect to interrupt () , not if y 0, and barging.
public class CountingSemaphore { private int value = 0; private int waitcount = 0; private int notifyCount = 0;
public CountingSemaphore(int initial)
( if (initial > 0) value = initial; 3
public synchronized void PO throws InterruptedException C if (value <= waitcount) ( waitCount++; try < do ( waito; ) while (notifycount == 0); 1 catch(InterruptedException e) ( notify0 ; throw e; 1 finally ( waitCount--; 3 notifyCount--; 1 else C if (not if yCount > waitcount) notifyCount--; 1 value-- ; 1
public synchronized void V() ( value++ ; if (waitcount > notifycount) ( notifyCount++; notify0 ; )
5 Conclusions The above sequence of attempts at a Java monitor im- plementing a counting semaphore clearly shows the dif- ficulties in writing correctly synchronized multithreaded Java programs. The Java monitor is really a low-level synchronization tool with many subtleties and race con- ditions, in contrast to the monitor theory one learns in an operating systems class. Unfortunately, the applica- tions programmer must struggle with these problems. Java needs additional class libraries that provide less troublesome, more user-friendly synchronization tools.
6 References
PI
PI
PI
PI
Andrews, G. R. Concurrent Programming: Princi- ples and Practice. Benjamin/Cummings, 1991.
Arnold, K., and Gosling, J. The Java Programming Language, 2”d ed. Addison-Wesley, 1998.
Buhr, P. A., Fortier, M., and Coffin, M. H. Moni- tor Classification. ACM %omputing Surveys 27, 1 (March 1995).
Gosling, J., Joy, B., and Steele, G. The Java Lan- guage Specification. Addison-Wesley, 1996.