📄 javaconc.html
字号:
public AppletRegistryObjectV0() { names = new String[CAPACITY]; apps = new Applet[CAPACITY]; len = 0; } public synchronized void add(String nm, Applet app) { if (len >= CAPACITY) return; names[len] = nm; apps[len] = app; ++len; } public synchronized Applet get(String nm) { for (int i = 0; i < len; ++i) if (names[i].equals(nm)) return apps[i]; return null; } public synchronized int entries() { return len; } public synchronized String nth(int i) { if (i >= len) return null; return names[i]; } public synchronized void remove(String nm) { for (int i = 0; i < len; ++i) { if (names[i].equals(nm)) { names[i] = names[len-1]; apps[i] = apps[len-1]; names[len-1] = null; apps[len-1] = null; --len; return; } } }</pre><p>A nice feature of Java synchronization policies is that code in onesynchronized method may make a self-call to another synchronizedmethod in the same object without blocking. (In some other concurrentlanguages, this could cause the call to wait forever!).<H3><a name="secGuards"></a>Guarded Actions</H3>Notice that, as defined above, method <code>AppletRegistry.add</code>does nothing at all if the array is full. This is clearly not a greatidea. But how should you deal with it? In a purely a sequentialsetting, you'd have only one choice, to raise some kind of <ahref="balking.html" tppabs="http://www.foi.hr/~dpavlin/java/mirrors/g.oswego.edu/dl/pats/balking.html">exception</a>. This might be a good choice heretoo, but in a concurrent setting, there's also the option of<em>delaying</em> execution of the method. That is, the caller couldbe suspended waiting for some other thread to invoke<code>remove</code>, thus freeing up a slot for an add.<p> Java supports mostly-classic mechanisms for implementing this andall other <em>guarded actions</em> (i.e., actions that are allowed tooccur only under the right conditions, otherwise delaying.) This styleof suspension is available via <code>wait</code>() and<code>notifyAll()</code>:<DL><DT> <CODE>wait()</CODE><DD> A call to <code>wait()</code> causes an object to sleep until a subsequent <code>notifyAll()</code> call is made from some other thread.<DT> <CODE>notifyAll()</CODE><DD> Suspended tasks in Java do not just automatically wake up. Resumption must instead be signalled explicitly, via method <CODE>notifyAll()</CODE>. This method wakes up all suspended activities that have been blocked via <code>waits</code> within any method of the <em>same</em> object. </DL>Notes:<ul> <li> Both <code>wait</code> and <code>notifyAll</code> are defined in <code>java.lang.Object</code>, so are present in all objects. <li> Java enforces the rule that both <code>wait</code> and <code>notifyAll</code> can be called <em>only</em> within <code>synchronized</code> methods. <li> Despite its name, <CODE>notifyAll</CODE> does not wake up all tasks in the entire program; only those waiting via a <CODE>wait</CODE> in methods of the target object. Calls to <CODE>wait</CODE> and <CODE>notifyAll</CODE> are normally self-calls, made within public synchronized methods of an object. <li> There are several minor variations of these methods also defined in <code>java.lang.Object</code>: Versions of <code>wait</code> with an agument specifying the maximum time to wait, and <code>notify()</code>, which wakes up at most one waiting thread.</ul><p>These methods form only the raw basis for synchronization.To use them for condition waits, you need to surround themwith context-dependent code that controls what conditionsare being managed. To return to the example, we couldrewrite the methods as follows:<pre> public synchronized void add(String nm, Applet app) { while (len >= capacity) { try { wait(); } catch(InterruptedException e) {} } names[len] = nm; apps[len] = app; ++len; } public synchronized void remove(String nm) { for (int i = 0; i < len; ++i) { if (names[i].equals(nm)) { names[i] = names[len-1]; apps[i] = apps[len-1]; names[len-1] = null; apps[len-1] = null; --len; notifyAll(); return; } } }</pre><p> As discussed in more depth in the context of general designprinciples for <a href="synchDesign.html" tppabs="http://www.foi.hr/~dpavlin/java/mirrors/g.oswego.edu/dl/pats/synchDesign.html"> synchronized objects</a>:<ul> <li> As a general rule, condition waits should always be placed in while loops as is done here. This is because when the action is resumed, the waiting task doesn't know if the condition is actually true; it only knows that it has been woken up. So it must check again. For example, while a simple <code>if</code> would work here in the code as given, it would start failing in peculiar ways if someone wrote a subclass of AppletRegistry that additionally used waits and notifies for some other purpose. <li> Like <code>sleep</code>, <code>wait</code> can be broken by an interruption. However, here, a more reasonable thing to do is to ignore the interruption and wait again. (An alternative is to re-throw the exception back to the caller.)</ul><p>This registry can now be used by applets like:<pre>public class RegisteredAppletV1 extends Applet { protected String nm_; protected TextArea txt_; protected boolean stopped_; public RegisteredAppletV1() { stopped_ = false; } public synchronized void start() { nm_ = getParameter("regname"); AppletRegistry.add(nm_, this); txt_ = new TextArea(4, 40); txt_.setEditable(true); setLayout(new BorderLayout()); add("South", txt_); add("North", new Button("Stop")); txt_.appendText(nm_); txt_.appendText(" Started\n"); txt_.repaint(); } public synchronized boolean action(Event evt, Object arg) { if ("Stop".equals(arg)) { stop(); return true; } return false; } public synchronized void stop() { if (!stopped_) { stopped_ = true; txt_.appendText(nm_); txt_.appendText(" Stopped\n"); txt_.repaint(); AppletRegistry.remove(nm_); for (int i = 0; i < AppletRegistry.entries(); ++i) { String appnm = AppletRegistry.nth(i); if (appnm != null) { Applet app = AppletRegistry.get(appnm); if (app != null) app.stop(); } } } } }</pre><a href="RegisteredAppletV1.html" tppabs="http://www.foi.hr/~dpavlin/java/mirrors/g.oswego.edu/dl/pats/RegisteredAppletV1.html">Run RegisteredAppletV1</a>.<h3>Statics and Per-Block Synchronization </h3>In addition to per-object locks, Java supports per-class locks, thatcan be used to arrange synchronized access to Java per-class<code>static</code> variables.<p> Except for <code>statics</code> representing <code>final</code>constants, or those initialized once during class load time (as in theRegistry example), using statics is not usually an especially goodidea in concurrent Java programs. However, they do justifiably arisefrom time to time. When they do, they must be specially dealtwith. The use of per-instance <code>synchronized</code> methods doesnot automatically preclude two instances of the same class fromrunning methods that mutually interfere with each other's use of<code>static</code> variables.<p>Methods accessing statics can be controlled using theJava per-block synchronization construct, that can occurwithin <em>any</em> normal Java method:<pre>synchronized(anObject) { anyCode();}</pre><p>In the case of statics, the object to synchronize on is the<code>Class</code> object of the current instance (availablefrom any Object via <code>getClass</code>).<p> For example, suppose a class maintains a count of those instancesthat are reading from a certain file. Access to the count may becontrolled via methods like:<pre>class Readers { private static int reading__ = 0; // never access this variable directly protected int reading() { synchronized(getClass()) { return reading__; } } protected void beginReading() { synchronized(getClass()) { ++reading__; } } protected void endReading() { synchronized(getClass()) { --reading__; } } // ...}</pre><h2><a name="secOther"></a>Other Java Concurrency Mechanisms</h2>This document has surveyed the most commonly used builtin Javaconcurrency primitives and Thread methods. There are a few others,that are useful in specialized situations. Usage is described in thecontext of particular patterns, including:<ul> <li> Variants of <code>wait</code> and <code>notifyAll</code> -- see <a href="synchDesign.html" tppabs="http://www.foi.hr/~dpavlin/java/mirrors/g.oswego.edu/dl/pats/synchDesign.html">Designing Objects for Concurrency</a>. <li> Partially synchonized methods -- see <a href="latches.html" tppabs="http://www.foi.hr/~dpavlin/java/mirrors/g.oswego.edu/dl/pats/latches.html">latches</a>. <li> Synchronizing on other objects -- see <a href="coordinators.html" tppabs="http://www.foi.hr/~dpavlin/java/mirrors/g.oswego.edu/dl/pats/coordinators.html"> coordinators</a> and <a href="trans.html" tppabs="http://www.foi.hr/~dpavlin/java/mirrors/g.oswego.edu/dl/pats/trans.html">transactions</a>. <li> Waiting out Threads and/or timing-out via <code>join</code> -- see <a href="waiters.html" tppabs="http://www.foi.hr/~dpavlin/java/mirrors/g.oswego.edu/dl/pats/waiters.html">waiters</a>.</ul><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: Wed Feb 21 11:22:52 EST 1996<!-- hhmts end --></body> </html>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -