⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 threads.doc.html

📁 A Java virtual machine instruction consists of an opcode specifying the operation to be performed, f
💻 HTML
📖 第 1 页 / 共 3 页
字号:
    int a = 1, b = 2;    void to() {    	a = 3;    	b = 4;    }    void fro()     	System.out.println("a= " + a + ", b=" + b);    }}</pre></blockquote>Now suppose that two threads are created and that one thread calls <code>to</code> while the other thread calls <code>fro</code>. What is the required set of actions and what are the ordering constraints?<p><a name="23987"></a>Let us consider the thread that calls <code>to</code>. According to the rules, this thread must perform an <i>assign</i> of <code>a</code> followed by an <i>assign</i> of <code>b</code>. That is the bare minimum required to execute a call to the method <code>to</code>. Because there is no synchronization, it is at the option of the implementation whether or not to <i>store</i> the assigned values back to main memory! Therefore, the thread that calls <code>fro</code> may obtain either <code>1</code> or <code>3</code> for the value of <code>a</code> and independently may obtain either <code>2</code> or <code>4</code> for the value of <code>b</code>.<p><a name="23988"></a>Now suppose that <code>to</code> is <code>synchronized</code> but <code>fro</code> is not:<p><blockquote><pre>class SynchSimple {    int a = 1, b = 2;    synchronized void to() {    	a = 3;    	b = 4;    }    void fro()     	System.out.println("a= " + a + ", b=" + b);    }}</pre></blockquote>In this case the method <code>to</code> will be forced to <i>store</i> the assigned values back to main memory before the <i>unlock</i> operation at the end of the method. The method <code>fro</code> must, of course, use <code>a</code> and <code>b</code> (in that order) and so must <i>load</i> values for <code>a</code> and <code>b</code> from main memory.<p><a name="24042"></a>The total set of operations may be pictured as follows:<br><br><img src="Threads.doc.anc2.gif"><br><br><p>Here an arrow from action <i>A</i> to action <i>B</i> indicates that <i>A</i> must precede <i>B</i>.<p><a name="24044"></a>In what order may the operations by the main memory occur? Note that the rules do not require that <i>write</i> <code>a</code> occur before <i>write</i> <code>b</code>; neither do they require that <i>read</i> <code>a</code> occur before <i>read</i> <code>b</code>. Also, even though method <code>to</code> is synchronized, method <code>fro</code> is not synchronized, so there is nothing to prevent the <i>read</i> operations from occurring between the <i>lock</i> and <i>unlock</i> operations. (The point is that declaring one method <code>synchronized</code> does not of itself make that method behave as if it were atomic.)<p><a name="24045"></a>As a result, the method <code>fro</code> could still obtain either <code>1</code> or <code>3</code> for the value of <code>a</code> and independently could obtain either <code>2</code> or <code>4</code> for the value of <code>b</code>. In particular, <code>fro</code> might observe the value <code>1</code> for <code>a</code> and <code>4</code> for <code>b</code>. Thus, even though <code>to</code> does an <i>assign</i> to <code>a</code> and then an <i>assign</i> to <code>b</code>, the <i>write</i> operations to main memory may be observed by another thread to occur as if in the opposite order. <p><a name="25553"></a>Finally, suppose that <code>to</code> and <code>fro</code> are both <code>synchronized</code>:<p><blockquote><pre>class SynchSynchSimple {    int a = 1, b = 2;    synchronized void to() {    	a = 3;    	b = 4;    }    synchronized void fro()     	System.out.println("a= " + a + ", b=" + b);    }}</pre></blockquote><a name="24057"></a>In this case, the actions of method <code>fro</code> cannot be interleaved with the actions of method <code>to</code>, and so <code>fro</code> will print either "<code>a=1, b=2</code>" or "<code>a=3, b=4</code>".<p><a name="22488"></a><hr><h2>8.12    Threads</h2>Threads are created and managed by the classes <code>Thread</code> and <code>ThreadGroup</code>. Creatinga <code>Thread</code> object creates a thread, and that is the only way to create a thread. When the thread is created, it is not yet active; it begins to run when its <code>start</code> method is called.<p><a name="22500"></a><hr><h2>8.13    Locks and Synchronization</h2>There is a lock associated with every object. The Java programming language does not provide a way to perform separate <i>lock</i> and <i>unlock</i> operations; instead, they are implicitly performed by high-level constructs that always arrange to pair such operationscorrectly. (The Java virtual machine, however, provides separate <i>monitorenter</i> and <i>monitorexit</i> instructions that implement the <i>lock</i> and <i>unlock</i> operations.)<p><a name="24410"></a>The <code>synchronized</code> statement computes a reference to an object; it then attempts to perform a <i>lock</i> operation on that object and does not proceed further until the <i>lock</i> operation has successfully completed. (A <i>lock</i> operation may be delayed because the rules about locks can prevent the main memory from participating until some other thread is ready to perform one or more <i>unlock</i> operations.) After the lock operation has been performed, the body of the <code>synchronized</code> statement is executed. Normally, a compiler for the Java programming language ensures that the <i>lock</i> operation implemented by a <i>monitorenter</i> instruction executed prior to the execution of the body of the <code>synchronized</code> statement is matched by an unlock operation implemented by a <i>monitorexit</i> instruction whenever the <code>synchronized</code> statement completes, whether completion is normal or abrupt.<p><a name="22509"></a>A <code>synchronized</code> method automatically performs a <i>lock</i> operation when it is invoked; its body is not executed until the <i>lock</i> operation has successfully completed. If the method is an instance method, it locks the lock associated with the instance for which it was invoked (that is, the object that will be known as <code>this</code> during execution of the method's body). If the method is <code>static</code>, it locks the lock associated with the <code>Class</code> object that represents the class in which the method is defined. If execution of the method's body is ever completed, either normally or abruptly, an <i>unlock</i> operation is automatically performed on that same lock.<p><a name="22510"></a>Best practice is that if a variable is ever to be assigned by one thread and used or assigned by another, then all accesses to that variable should be enclosed in <code>synchronized</code> methods or <code>synchronized</code> statements.<p><a name="24717"></a>Although a compiler for the Java programming language normally guarantees structured use of locks (see <a href="Compiling.doc.html#6530">Section 7.14, "Synchronization"</a>), there is no assurance that all code submitted to the Java virtual machine will obey this property. Implementations of the Java virtual machine are permitted but not required to enforce both of the following two rules guaranteeing structured locking.<p><a name="24721"></a>Let <i>T</i> be a thread and <i>L</i> be a lock. Then:<p><ol><a name="24722"></a><li>The number of <i>lock</i> operations performed by <i>T</i> on <i>L</i> during a method invocation must equal the number of <i>unlock</i> operations performed by <i>T</i> on <i>L</i> during the method invocation whether the method invocation completes normally or abruptly. <p><a name="24623"></a><li>At no point during a method invocation may the number of <i>unlock</i> operations performed by <i>T</i> on <i>L</i> since the method invocation exceed the number of <i>lock</i> operations performed by <i>T</i> on <i>L </i>since the method invocation.</ol>In less formal terms, during a method invocation every <i>unlock</i> operation on <i>L</i> must match some preceding <i>lock</i> operation on <i>L</i>. <p><a name="25011"></a>Note that the locking and unlocking automatically performed by the Java virtual machine when invoking a synchronized method are considered to occur during the calling method's invocation.<p><a name="24566"></a><hr><h2>8.14    Wait Sets and Notification</h2>Every object, in addition to having an associated lock, has an associated wait set, which is a set of threads. When an object is first created, its wait set is empty.<p><a name="23519"></a>Wait sets are used by the methods <code>wait</code>, <code>notify</code>, and <code>notifyAll</code> of class <code>Object</code>. These methods also interact with the scheduling mechanism for threads.<p><a name="23520"></a>The method <code>wait</code> should be invoked for an object only when the current thread (call it <i>T &#32;</i>) has already locked the object's lock. Suppose that thread <i>T</i> has in fact performed <i>N</i> <i>lock</i> operations on the object that have not been matched by <i>unlock</i> operations on that same object. The <code>wait</code> method then adds the current thread to the wait set for the object, disables the current thread for thread scheduling purposes, and performs <i>N</i> <i>unlock</i> operations on the object to relinquish the lock on it. Locks having been locked by thread <i>T</i> on objects other than the one <i>T</i> is to wait on are not relinquished. The thread <i>T</i> then lies dormant until one of three things happens:<p><ul><li>Some other thread invokes the <code>notify</code> method for that object, and thread <i>T</i> happens to be the one arbitrarily chosen as the one to notify.<p><li>Some other thread invokes the <code>notifyAll</code> method for that object.<p><li>If the call by thread <i>T</i> to the <code>wait</code> method specified a time-out interval, then the specified amount of real time elapses.</ul><a name="23527"></a>The thread <i>T</i> is then removed from the wait set and reenabled for thread scheduling. It then locks the object again (which may involve competing in the usual manner with other threads); once it has gained control of the lock, it performs <i>N</i> - <i>1</i> additional <i>lock</i> operations on that same object and then returns from the invocation of the <code>wait</code> method. Thus, on return from the <code>wait</code> method, the state of the object's lock is exactly as it was when the <code>wait</code> method was invoked.<p><a name="23528"></a>The <code>notify</code> method should be invoked for an object only when the current thread has already locked the object's lock, or an <code>IllegalMonitorStateException</code> will be thrown. If the wait set for the object is not empty, then some arbitrarily chosen thread is removed from the wait set and reenabled for thread scheduling. (Of course, that thread will not be able to proceed until the current thread relinquishes the object's lock.)<p><a name="23537"></a>The <code>notifyAll</code> method should be invoked for an object only when the current thread has already locked the object's lock, or an <code>IllegalMonitorStateException</code> will be thrown. Every thread in the wait set for the object is removed from the wait set and reenabled for thread scheduling. (Those threads will not be able to proceed until the current thread relinquishes the object's lock.)<p><a name="23512"></a><p><hr><!-- This inserts footnotes--><p><a href="VMSpecTOC.doc.html">Contents</a> | <a href="Compiling.doc.html">Prev</a> | <a href="Mnemonics.doc.html">Next</a> | <a href="VMSpecIX.fm.html">Index</a><p><font size="-1"><i>The Java</i><sup><font size=-2>TM</font></sup><i> Virtual Machine Specification </i><br><!-- HTML generated by Suzette Pelouch on March 31, 1999 --><i><a href="Copyright.doc.html">Copyright &#169 1999 Sun Microsystems, Inc.</a>All rights reserved</i><br>Please send any comments or corrections to <a href="mailto:jvm@java.sun.com">jvm@java.sun.com</a></font></body></html>

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -