📄 synchdesign.html
字号:
loops as is done here. This is because when an action is resumed, thewaiting task doesn't know if the condition is actually true; it onlyknows that it has been woken up. So it must check again. This styleshould be used even if the code contains only a single kind of wait,waiting for a single kind of condition. Otherwise such code will startfailing in peculiar ways if people make subclasses of your class thatadditionally use waits and notifies for some other purpose. <blockquote>Footnote: This is one aspect of the so-called ``inheritance anomaly'' inconcurrent object-oriented programming (see for example <ahref="javascript:if(confirm('ftp://camille.is.s.u-tokyo.ac.jp/pub/papers/README.html \n\nThis file was not retrieved by Teleport Pro, because it is addressed on a domain or path outside the boundaries set for its Starting Address. \n\nDo you want to open it from the server?'))window.location='ftp://camille.is.s.u-tokyo.ac.jp/pub/papers/README.html'" tppabs="ftp://camille.is.s.u-tokyo.ac.jp/pub/papers/README.html"> papersby Satoshi Matsuoka</a>), that applied to Java mainly says that thatthe more your synchronization code is specialized around particularcontexts, the less likely it is that people will be able to makeuseful subclasses. Java avoids some of the most difficultto cope with aspects of inheritance anomalies because it does notforce (or even allow) programmers to associate guard conditions withparticular ``wait queues'', as is true in many monitor-basedconcurrent programming languages. While per-condition wait queuesare sometimes more efficient, they are also fragile and inflexible.<p>As a design convention, if you ever find yourself needing to useone of the constructs described in these patterns as fragile orleading to subclassing problems, you could mark that class as<code>final</code>, so that people will not be able to subclass it.</blockquote><p>Generally, the only kinds of (minor) exceptions to this codingidiom occur for <a href="latches.html" tppabs="http://www.foi.hr/~dpavlin/java/mirrors/g.oswego.edu/dl/pats/latches.html">latches</a>, conditionsthat change state at most once.<p> Like <code>sleep</code>, <code>wait</code> can be broken by aninterruption. Normally the only things you can do about<code>InterruptedExceptions</code> in guard loops are to ignore them(thus re-evaluating the condition and re-waiting) which at leastpreserves safety at the possible expense of liveness, or alternativelyto kick the exception up to some caller who is prepared to handle it,which preserves liveness but requires that the object catching theexception know how to re-establish consistent states to preservesafety. In most examples, we'll do the former, mainly just forsimplicity.<p><CODE>Wait</CODE>-based constructions represent only one side of guardtranslation. The other side consists of inserting code to to wake upwaiting threads when the conditions that they are waiting for changevalue. <EM>Every</EM> time the value of any variable or objectmentioned in a guard changes value in a way that might affect thetruth value of the condition, suspended tasks must be woken up via acall to <CODE>notifyAll</CODE>. The simplest way to do this is justto insert <CODE>notifyAll</CODE>s in methods that cause state changes.<p> For example, here is a first pass at translating the <AHREF="#secCounter">BoundedCounter</A>. (Several variants andimprovements of this example are described in other design patterns inthis set of documents.)<PRE>class BoundedCounterV1 implements BoundedCounter { public synchronized int value() { return count_; } public synchronized void inc() { waitUntilIncrementable(); ++count_; notifyAll(); } public synchronized void dec() { waitUntilDecrementable(); --count_; notifyAll(); } public BoundedCounterV1() { count_ = minValue; } private int count_; private synchronized void waitUntilIncrementable() { while (count_ >= maxVal) { try { wait(); } catch(InterruptedException ex) {}; } private synchronized void waitUntilDecrementable() { while (count_ <= minVal) try { wait(); } catch(InterruptedException ex) {}; }}</PRE><p>Here, both the <CODE>inc</CODE> and <CODE>dec</CODE> methods affectthe <CODE>count_</CODE> variable, so they each contain a<CODE>notifyAll</CODE> to wake up threads that may be waiting for thevalue to change.<P> It is sometimes possible to replace <CODE>notifyAll</CODE> with acheaper method, <CODE>notify</CODE> (defined in<CODE>java.Object</CODE>). <CODE>Notify()</CODE> wakes up only onewaiting thread. It is occasionally useful as a performance measurewhen you know that there is at most one affected waiting thread, but,as with most shortcuts, limits extensibility. (See <ahref="acceptor.html" tppabs="http://www.foi.hr/~dpavlin/java/mirrors/g.oswego.edu/dl/pats/acceptor.html">Event Loops</a> for a usage example.)<p>You can also use a single <CODE>notify</CODE> if you arrange tocascade notifications so that each notified thread wakes up the nextone, even if it itself cannot proceed so must re-wait. However, themechanics for doing a full cascade are error-prone and typically justas expensive, or even moreso than using <CODE>notifyAll</CODE>. Sothis technique is limited to very special cases. <P>Failure to call <CODE>notifyAll</CODE> when it is necessary is acommon programming error. Such errors can be minimized by adoptingstandard designs and programming conventions that ensure that suchcalls get performed. The most radically conservative solution is toplace a <CODE>notifyAll</CODE> after <EM>every</EM> statement that maycause a state change. This may lead to too many useless signals andhorrible performance. (<CODE>NotifyAll</CODE> is a relativelyexpensive operation.) Also it can run against the otherwise goodgeneral practice of always placing <CODE>notify</CODE>s as the<CODE>final</CODE> statement(s) of a method (see for example <AHREF="javascript:if(confirm('http://plg.uwaterloo.ca/~pabuhr \n\nThis file was not retrieved by Teleport Pro, because it is addressed on a domain or path outside the boundaries set for its Starting Address. \n\nDo you want to open it from the server?'))window.location='http://plg.uwaterloo.ca/~pabuhr'" tppabs="http://plg.uwaterloo.ca/~pabuhr">papers by Peter Buhr</A>).This avoids having to think through the complexities that can occur(and the underlying infrastructure implementation decisions made bythe Java runtime system) when both the signalling and signalled taskwant to continue executing. <P>However, as a design practice, it is sometimes a good idea tostart out using blanket notifications, and then to minimizeand reorganize them using the techniques described in otherdesign patterns presented in this set of documents.<h3><a name="secAssign"></a>Encapsulating Assignment</h3><p> One of the simplest ways to implement blanket notificationsdealing with instance variables is to implement a non-public methodthat encapsulates assignment, issuing a notification upon any kind ofchange. For example, we could rewrite the <AHREF="synchDesign.html#secCounter" tppabs="http://www.foi.hr/~dpavlin/java/mirrors/g.oswego.edu/dl/pats/synchDesign.html#secCounter">BoundedCounter</A> example as:<PRE>class BoundedCounterV2 implements BoundedCounter { public synchronized int value() { return count_; } public synchronized void inc() { waitUntilIncrementable(); value(count_+1); } public synchronized void dec() { waitUntilDecrementable(); value(count_-1); } public BoundedCounterV2() { count_ = minValue; } private int count_; private void value(int newval) { count_ = newval; notifyAll(); } private synchronized void waitUntilIncrementable() { while (count_ >= maxVal) try { wait(); } catch(InterruptedException ex) {}; } private synchronized void waitUntilDecrementable() { while (count_ <= minVal) try { wait(); } catch(InterruptedException ex) {}; }}</PRE><p><a href="aopintro.html" tppabs="http://www.foi.hr/~dpavlin/java/mirrors/g.oswego.edu/dl/pats/aopintro.html">[Concurrent Programming in Java]</a><hr><address><A HREF="javascript:if(confirm('http://g.oswego.edu/dl \n\nThis file was not retrieved by Teleport Pro, because it is addressed on a domain or path outside the boundaries set for its Starting Address. \n\nDo you want to open it from the server?'))window.location='http://g.oswego.edu/dl'" tppabs="http://g.oswego.edu/dl">Doug Lea</A></address><!-- hhmts start -->Last modified: Tue Feb 20 06:29:00 EST 1996<!-- hhmts end --></body> </html>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -