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

📄 threads.doc.html

📁 Jvm 规范说明。The Java Virtual Machine was designed to support the Java programming language. Some concep
💻 HTML
📖 第 1 页 / 共 3 页
字号:
<li>A <i>lock</i> operation by T<em></em> on L<i></i> may occur only if, for every thread S<i></i> other than T<em></em>, the number of preceding <i>unlock</i> operations by S<i></i> on L<i></i> equals the number of preceding <i>lock</i> operations by S<i></i> on L. (Less formally: only one thread at a time is permitted to lay claim to a lock; moreover, a thread may acquire the same lock multiple times and does not relinquish ownership of it until a matching number of <i>unlock</i> operations have been performed.)
<a name="22251"></a>
<li>An <i>unlock</i> operation by thread T<em></em> on lock L<i></i> may occur only if the number of preceding <i>unlock</i> operations by T<em></em> on L<i></i> is strictly less than the number of preceding <i>lock</i> operations by T<em></em> on L<i></i>. (Less formally: a thread is not permitted to unlock a lock it does not own.)
</ul><a name="22252"></a>
With respect to a lock, the <i>lock</i> and <i>unlock</i> operations performed by all the threads 
are performed in some total sequential order. This total order must be consistent 
with the total order on the operations of each thread.
<p><a name="22253"></a>
<hr><h2>8.6	 Rules About the Interaction of Locks and Variables</h2>
<a name="22254"></a>
Let T<em></em> be any thread, let V<i></i> be any variable, and let L<i></i> be any lock. There are certain 
constraints on the operations performed by T<em></em> with respect to V<i></i> and L<i></i>:
<p><ul><a name="22255"></a>
<li>Between an <i>assign</i> operation by T<em></em> on V<i></i> and a subsequent <i>unlock</i> operation by T<em></em> on L<i></i>, a <i>store</i> operation by T<em></em> on V<i></i> must intervene; moreover, the <i>write</i> operation corresponding to that <i>store</i> must precede the <i>unlock</i> operation, as seen by main memory. (Less formally: if a thread is to perform an <i>unlock</i> operation on <i>any</i> lock, it must first copy <i>all</i> assigned values in its working memory back out to main memory.)
<a name="22256"></a>
<li>Between a <i>lock</i> operation by T<em></em> on L<i></i> and a subsequent <i>use</i> or <i>store</i> operation by T<em></em> on a variable V<i></i>, an <i>assign</i> or <i>load</i> operation on <i>V</i> must intervene; moreover, if it is a <i>load</i> operation, then the <i>read</i> operation corresponding to that <i>load</i> must follow the <i>lock</i> operation, as seen by main memory. (Less formally: a <i>lock</i> operation behaves as if it flushes <i>all</i> variables from the thread's working memory, after which it must either assign them itself or load copies anew from main memory.)
</ul><a name="22258"></a>
<hr><h2>8.7	 Rules for Volatile Variables</h2>
<a name="22259"></a>
If a variable is declared volatile, then additional constraints apply to the operations of each thread. Let T<em></em> be a thread and let V<i></i> and W be volatile variables.
<p><ul><a name="22260"></a>
<li>A <i>use</i> operation by T<em></em> on V<i></i> is permitted only if the previous operation by T<em></em> on V<i></i> was <i>load</i>, and a <i>load</i> operation by T<em></em> on V<i></i> is permitted only if the next operation by T<em></em> on V<i></i> is <i>use</i>. The <i>use</i> operation is said to be "associated" with the <i>read</i> operation that corresponds to the <i>load</i>.
<a name="22261"></a>
<li>A <i>store</i> operation by T<em></em> on V<i></i> is permitted only if the previous operation by T<em></em> on V<i></i> was <i>assign</i>, and an <i>assign</i> operation by T<em></em> on V<i></i> is permitted only if the next operation by T<em></em> on V<i></i> is <i>store</i>. The <i>assign</i> operation is said to be "associated" with the <i>write</i> operation that corresponds to the <i>store</i>.
<a name="22262"></a>
<li>Let action A be a <i>use</i> or <i>assign</i> by thread T<em></em> on variable V<i></i>, let action F be the <i>load</i> or <i>store</i> associated with A, and let action P be the <i>read</i> or <i>write</i> of V<i></i> that corresponds to F. Similarly, let action B be a <i>use</i> or <i>assign</i> by thread T<em></em> on variable W<i></i>, let action G be the <i>load</i> or <i>store</i> associated with B, and let action Q be the <i>read</i> or <i>write</i> of V<i></i> that corresponds to G<i></i>. If A precedes B, then P must precede Q. (Less formally: operations on the master copies of volatile variables on behalf of a thread are performed by the main memory in exactly the order that the thread requested.)
</ul><a name="24432"></a>
<hr><h2>8.8	 Prescient Store Operations</h2>
<a name="24433"></a>
If a variable is not declared <code>volatile</code>, then the rules in the previous sections are 
relaxed slightly to allow <i>store</i> operations to occur earlier than would otherwise be 
permitted. The purpose of this relaxation is to allow optimizing Java compilers to 
perform certain kinds of code rearrangement that preserve the semantics of properly synchronized programs, but might be caught in the act of performing memory 
operations out of order by programs that are not properly synchronized.
<p><a name="24434"></a>
Suppose that a <i>store</i> by T of V would follow a particular <i>assign</i> by T of V according to the rules of the previous sections, with no intervening <i>load</i> or <i>assign</i> by T of V. Then that <i>store</i> operation would send to the main memory the value that the <i>assign</i> operation put into the working memory of thread T. The special rule allows the <i>store</i> operation actually to occur before the <i>assign</i> operation instead, if the following restrictions are obeyed:<p>
<ul><a name="24435"></a>
<li>If the <i>store</i> operation occurs, the <i>assign</i> is bound to occur. (Remember, these are restrictions on what actually happens, not on what a thread plans to do. No fair performing a <i>store</i> and then throwing an exception before the <i>assign</i> occurs!)
<a name="24436"></a>
<li>No <i>lock</i> operation intervenes between the relocated <i>store</i> and the <i>assign</i>.
<a name="24437"></a>
<li>No <i>load</i> of V intervenes between the relocated <i>store</i> and the <i>assign</i>.
<a name="24438"></a>
<li>No other <i>store</i> of V intervenes between the relocated <i>store</i> and the <i>assign</i>.
<a name="24439"></a>
<li>The <i>store</i> operation sends to the main memory the value that the <i>assign</i> operation will put into the working memory of thread T. 
</ul><a name="24440"></a>
This last property inspires us to call such an early <i>store</i> operation <i>prescient</i>: it has 
to know ahead of time, somehow, what value will be stored by the <i>assign</i> that it 
should have followed. In practice, optimized compiled code will compute such 
values early (which is permitted if, for example, the computation has no side 
effects and throws no exceptions), store them early (before entering a loop, for 
example), and keep them in working registers for later use within the loop.
<p><a name="22263"></a>
<hr><h2>8.9	 Discussion</h2>
<a name="22264"></a>
Any association between locks and variables is purely conventional. Locking 
any lock conceptually flushes <i>all</i> variables from a thread's working memory, 
and unlocking any lock forces the writing out to main memory of <i>all</i> variables 
that the thread has assigned. That a lock may be associated with a particular 
object or a class is purely a convention. In some applications, it may be appropriate always to lock an object before accessing any of its instance variables, for 
example; <code>synchronized</code> methods are a convenient way to follow this convention. In other applications, it may suffice to use a single lock to synchronize 
access to a large collection of objects.
<p><a name="22265"></a>
If a thread uses a particular shared variable only after locking a particular lock and before the corresponding unlocking of that same lock, then the thread will read the shared value of that variable from main memory after the <i>lock</i> operation, if necessary, and will copy back to main memory the value most recently assigned to that variable before the <i>unlock</i> operation. This, in conjunction with the mutual exclusion rules for locks, suffices to guarantee that values are correctly transmitted from one thread to another through shared variables.<p>
<a name="22266"></a>
The rules for volatile variables effectively require that main memory be touched exactly once for each <i>use</i> or <i>assign</i> of a volatile variable by a thread, and that main memory be touched in exactly the order dictated by the thread execution semantics. However, such memory operations are not ordered with respect to <i>read</i> and <i>write</i> operations on nonvolatile variables.<p>
<a name="23865"></a>
<hr><h2>8.10	 Example: Possible Swap</h2>
<a name="23866"></a>
Consider a class that has class variables <code>a</code> and <code>b</code> and methods <code>hither</code> and <code>yon</code>:
<p><pre><br><a name="23867"></a>&nbsp;&nbsp;&nbsp;&nbsp;class Sample {
</pre><pre>&nbsp;&nbsp;&nbsp;&nbsp;	int a = 1, b = 2;
&nbsp;&nbsp;&nbsp;&nbsp;	void hither() {
&nbsp;&nbsp;&nbsp;&nbsp;		a = b;
&nbsp;&nbsp;&nbsp;&nbsp;	}
&nbsp;&nbsp;&nbsp;&nbsp;	void yon() 
&nbsp;&nbsp;&nbsp;&nbsp;		b = a;
&nbsp;&nbsp;&nbsp;&nbsp;	}
<a name="23875"></a>&nbsp;&nbsp;&nbsp;&nbsp;}
<br></pre><a name="23876"></a>
Now suppose that two threads are created, and that one thread calls <code>hither</code> while 
the other thread calls <code>yon</code>. What is the required set of actions and what are the 
ordering constraints?
<p><a name="23877"></a>
Let us consider the thread that calls <code>hither</code>. According to the rules, this thread must perform a <i>use</i> of <code>b</code> followed by an <i>assign</i> of <code>a</code>. That is the bare minimum required to execute a call to the method <code>hither</code>.<p>
<a name="23878"></a>
Now, the first operation on variable <code>b</code> by the thread cannot be <i>use</i>. But it may be <i>assign</i> or <i>load</i>. An <i>assign</i> to <code>b</code> cannot occur because the program text does not call for such an <i>assign</i> operation, so a <i>load</i> of <code>b</code> is required. This <i>load</i> operation by the thread in turn requires a preceding <i>read</i> operation for <code>b</code> by the main memory.<p>
<a name="23879"></a>
The thread may optionally <i>store</i> the value of <code>a</code> after the <i>assign</i> has occurred. If it does, then the <i>store</i> operation in turn requires a following <i>write</i> operation for <code>a</code> by the main memory.<p>
<a name="23880"></a>
The situation for the thread that calls <code>yon</code> is similar, but with the roles of <code>a</code> and <code>b</code> exchanged.<p>
<a name="23908"></a>
The total set of operations may be pictured as follows:<br><br><img src="Threads.doc.anc.gif">
<br><br><p>
<a name="23909"></a>
Here an arrow from action A to action B indicates that A must precede B.
<p><a name="24312"></a>
In what order may the operations by the main memory occur? The only constraint is that it is not possible both for the <i>write</i> of <code>a</code> to precede the <i>read</i> of <code>a</code> and for the <i>write</i> of <code>b</code> to precede the <i>read</i> of <code>b</code>, because the causality arrows in the diagram would form a loop so that an action would have to precede itself, which is not allowed. Assuming that the optional <i>store</i> and <i>write</i> operations are to occur, there are three possible orderings in which the main memory might legitimately perform its operations. Let <code>ha</code> and <code>hb</code> be the working copies of <code>a</code> and <code>b</code> for the <code>hither</code> thread, let <code>ya</code> and <code>yb</code> be the working copies for the <code>yon</code> thread, and let <code>ma</code> and <code>mb</code> be the master copies in main memory. Initially <code>ma=1</code> and <code>mb=2</code>. Then the three possible orderings of operations and the resulting states are as follows:<p>
<ul><a name="24313"></a>
<li><i>write</i> <code>a</code><code><img src="chars/arrwrite.gif"></code><i>read</i> <code>a</code>, <i>read</i> <code>b</code><code><img src="chars/arrwrite.gif"></code><i>write</i> <code>b</code> (then <code>ha=2</code>, <code>hb=2</code>, <code>ma=2</code>, <code>mb=2</code>, <code>ya=2</code>, <code>yb=2</code>)
<a name="24325"></a>
<li><i>read</i> <code>a</code><code><img src="chars/arrwrite.gif"></code><i>write</i> <code>a</code>, <i>write</i> <code>b</code><code><img src="chars/arrwrite.gif"></code><i>read</i> <code>b</code> (then <code>ha=1</code>, <code>hb=1</code>, <code>ma=1</code>, <code>mb=1</code>, <code>ya=1</code>, <code>yb=1</code>)
<a name="24326"></a>
<li><i>read</i> <code>a</code><code><img src="chars/arrwrite.gif"></code><i>write</i> <code>a</code>, <i>read</i> <code>b</code><code><img src="chars/arrwrite.gif"></code><i>write</i> <code>b</code> (then <code>ha=2</code>, <code>hb=2</code>, <code>ma=2</code>, <code>mb=1</code>, <code>ya=1</code>, <code>yb=1</code>)
</ul><a name="24327"></a>
Thus, the net result might be that, in main memory, <code>b</code> is copied into <code>a</code>, <code>a</code> is copied 
into <code>b</code>, or the values of <code>a</code> and <code>b</code> are swapped; moreover, the working copies of the 
variables might or might not agree. It would be incorrect, of course, to assume that 
any one of these outcomes is more likely than another. This is one place in which 
the behavior of a Java program is necessarily timing-dependent.
<p><a name="23915"></a>
Of course, an implementation might also choose not to perform the <i>store</i> and <i>write</i> operations, or only one of the two pairs, leading to yet other possible results.<p>
<a name="23916"></a>
Now suppose that we modify the example to use <code>synchronized</code> methods:<p>
<pre><br><a name="23917"></a>&nbsp;&nbsp;&nbsp;&nbsp;class SynchSample {
</pre><pre>&nbsp;&nbsp;&nbsp;&nbsp;	int a = 1, b = 2;
&nbsp;&nbsp;&nbsp;&nbsp;	synchronized void hither() {
&nbsp;&nbsp;&nbsp;&nbsp;		a = b;
&nbsp;&nbsp;&nbsp;&nbsp;	}
&nbsp;&nbsp;&nbsp;&nbsp;	synchronized void yon() 
&nbsp;&nbsp;&nbsp;&nbsp;		b = a;
&nbsp;&nbsp;&nbsp;&nbsp;	}
<a name="23925"></a>&nbsp;&nbsp;&nbsp;&nbsp;}
<br></pre><a name="23926"></a>
Let us again consider the thread that calls <code>hither</code>. According to the rules, this 
thread must perform a <i>lock</i> operation (on the <code>Class</code> object for class <code>SynchSample</code>) 
before the body of method <code>hither</code> is executed. This is followed by a <i>use</i> of <code>b</code> and 
then an <i>assign</i> of <code>a</code>. Finally, an <i>unlock</i> operation on the <code>Class</code> object must be performed after the body of method <code>hither</code> completes. That is the bare minimum 
required to execute a call to the method <code>hither</code>.
<p><a name="23927"></a>
As before, a <i>load</i> of <code>b</code> is required, which in turn requires a preceding <i>read</i> operation for <code>b</code> by the main memory. Because the <i>load</i> follows the <i>lock</i> operation, the corresponding <i>read</i> must also follow the <i>lock</i> operation.<p>
<a name="23928"></a>
Because an <i>unlock</i> operation follows the <i>assign</i> of <code>a</code>, a <i>store</i> operation on <code>a</code> is mandatory, which in turn requires a following <i>write</i> operation for <code>a</code> by the main memory. The <i>write</i> must precede the <i>unlock</i> operation.<p>
<a name="23929"></a>
The situation for the thread that calls <code>yon</code> is similar, but with the roles of <code>a</code> and <code>b</code> exchanged.<p>

⌨️ 快捷键说明

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