📄 17.doc.html
字号:
In the rules that follow, the phrasing "<i>B</i> must intervene between <i>A</i> and <i>C</i>" means that action <i>B</i> must follow action <i>A</i> and precede action <i>C</i>.<p>
<a name="28654"></a>
<h2>17.3 Rules about Variables</h2>
<a name="28308"></a>
Let <i>T</i> be a thread and <i>V</i><i></i> be a variable. There are certain constraints on the actions
performed by <i>T</i><em></em> with respect to <i>V</i>:
<p><ul><a name="28309"></a>
<li>An <i>use</i> or <i>assign</i> by <i>T</i><em></em> of <i>V</i><i></i> is permitted only when dictated by execution by <i>T</i><em></em> of the Java program according to the standard Java execution model. For example, an occurrence of <i>V</i><i></i> as an operand of the <code>+</code> operator requires that a single <i>use</i> action occur on <i>V</i><i></i>; an occurrence of <i>V</i><i></i> as the left-hand operand of the assignment operator <code>=</code> requires that a single <i>assign</i> action occur. All <i>use</i> and <i>assign</i> actions by a given thread must occur in the order specified by the program being executed by the thread. If the following rules forbid <i>T</i><em></em> to perform a required <i>use</i> as its next action, it may be necessary for <i>T</i><em></em> to perform a <i>load </i>first in order to make progress.
<a name="28310"></a>
<li>A <i>store</i> action by <i>T</i><em></em> on <i>V</i><i></i> must intervene between an <i>assign</i> by <i>T</i><em></em> of <i>V</i><i></i> and a subsequent <i>load</i> by <i>T</i><em></em> of <i>V</i><i></i>. (Less formally: a thread is not permitted to lose its most recent assign.)
<a name="28312"></a>
<li>An <i>assign</i> action by <i>T</i><em></em> on <i>V</i><i></i> must intervene between a <i>load</i> or <i>store</i> by <i>T</i><em></em> of <i>V</i> and a subsequent <i>store</i> by <i>T</i><em></em> of <i>V</i><i></i>. (Less formally: a thread is not permitted to write data from its working memory back to main memory for no reason.)
<a name="28313"></a>
<li>After a thread is created, it must perform an <i>assign</i> or <i>load</i> action on a variable before performing a <i>use</i> or <i>store</i> action on that variable. (Less formally: a new thread starts with an empty working memory.)
</ul><ul><a name="28314"></a>
<li>After a variable is created, every thread must perform an <i>assign</i> or <i>load</i> action on that variable before performing a <i>use</i> or <i>store</i> action on that variable. (Less formally: a new variable is created only in main memory and is not initially in any thread's working memory.)
</ul><a name="28315"></a>
Provided that all the constraints above and below are obeyed, a <i>load</i> or <i>store</i> action may be issued at any time by any thread on any variable, at the whim of the implementation.<p>
<a name="28317"></a>
There are also certain constraints on the <i>read</i> and <i>write</i> actions performed by main memory:<p>
<ul><a name="28318"></a>
<li>For every <i>load</i> action performed by any thread <i>T</i><em></em> on its working copy of a variable <i>V</i><i></i>, there must be a corresponding preceding <i>read</i> action by the main memory on the master copy of <i>V</i><i></i>, and the <i>load</i> action must put into the working copy the data transmitted by the corresponding <i>read</i> action.
<a name="28319"></a>
<li>For every <i>store</i> action performed by any thread <i>T</i><em></em> on its working copy of a variable <i>V</i><i></i>, there must be a corresponding following <i>write</i> action by the main memory on the master copy of <i>V</i><i></i>, and the <i>write</i> action must put into the master copy the data transmitted by the corresponding <i>store</i> action.
<a name="28786"></a>
<li>Let action <i>A</i> be a <i>load</i> or <i>store</i> by thread <i>T</i><em></em> on variable <i>V</i><i></i>, and let action <i>P</i> be the corresponding <i>read</i> or <i>write</i> by the main memory on variable <i>V</i><i></i>. Similarly, let action <i>B</i><i> </i>be some other <i>load</i> or <i>store</i> by thread <i>T</i><em></em> on that same variable <i>V</i><i></i>, and let action <i>Q</i> be the corresponding <i>read</i> or <i>write</i> by the main memory on variable <i>V</i><i></i>. If <i>A</i> precedes <i>B</i>, then <i>P</i> must precede <i>Q</i>. (Less formally: actions on the master copy of any given variable on behalf of a thread are performed by the main memory in exactly the order that the thread requested.)
</ul><a name="28817"></a>
Note that this last rule applies <i>only</i> to actions by a thread on the <i>same</i> variable.
However, there is a more stringent rule for <code>volatile</code> variables <a href="17.doc.html#28330">(§17.7)</a>.
<p><a name="28733"></a>
<h2>17.4 Nonatomic Treatment of <code>double</code> and <code>long</code></h2>
<a name="28740"></a>
If a <code>double</code> or <code>long</code> variable is not declared <code>volatile</code>, then for the purposes of
<i>load</i>, <i>store</i>, <i>read</i>, and <i>write</i> actions they are treated as if they were two variables of
32 bits each: wherever the rules require one of these actions, two such actions are
performed, one for each 32-bit half. The manner in which the 64 bits of a <code>double</code>
or <code>long</code> variable are encoded into two 32-bit quantities is implementation-dependent.
<p><a name="28747"></a>
This matters only because a <i>read</i> or <i>write</i> of a <code>double</code> or <code>long</code> variable may be handled by an actual main memory as two 32-bit <i>read</i> or <i>write</i> actions that may be separated in time, with other actions coming between them. Consequently, if two threads concurrently assign distinct values to the same shared non-<code>volatile</code> <code>double</code> or <code>long</code> variable, a subsequent use of that variable may obtain a value that is not equal to either of the assigned values, but some implementation-dependent mixture of the two values.<p>
<a name="28746"></a>
An implementation is free to implement <i>load</i>, <i>store</i>, <i>read</i>, and <i>write</i> actions for <code>double</code> and <code>long</code> values as atomic 64-bit actions; in fact, this is strongly encouraged. The model divides them into 32-bit halves for the sake of several currently popular microprocessors that fail to provide efficient atomic memory transactions on 64-bit quantities. It would have been simpler for Java to define all memory transactions on single variables as atomic; this more complex definition is a pragmatic concession to current hardware practice. In the future this concession may be eliminated. Meanwhile, programmers are cautioned always to explicitly synchronize access to shared <code>double</code> and <code>long</code> variables.<p>
<a name="28320"></a>
<h2>17.5 Rules about Locks</h2>
<a name="28321"></a>
Let <i>T</i><em></em> be a thread and <i>L</i> be a lock. There are certain constraints on the actions performed
by <i>T</i><em></em> with respect to <i>L</i>:
<p><ul><a name="28322"></a>
<li>A <i>lock</i> action by <i>T</i><em></em> on <i>L</i> may occur only if, for every thread <i>S</i><i></i> other than <i>T</i><em></em>, the number of preceding <i>unlock</i> actions by <i>S</i><i></i> on <i>L</i> equals the number of preceding <i>lock</i> actions by <i>S</i><i></i> on <i>L</i>. (Less formally: only one thread at a time is permitted to lay claim to a lock, and moreover a thread may acquire the same lock multiple times and doesn't relinquish ownership of it until a matching number of <i>unlock</i> actions have been performed.)
<a name="28763"></a>
<li>An <i>unlock</i> action by thread <i>T</i><em></em> on lock <i>L</i> may occur only if the number of preceding <i>unlock</i> actions by <i>T</i> on <i>L</i> is strictly less than the number of preceding <i>lock</i> actions by <i>T</i><em></em> on <i>L</i>. (Less formally: a thread is not permitted to unlock a lock it doesn't own.)
</ul><a name="28324"></a>
With respect to a lock, the <i>lock</i> and <i>unlock</i> actions performed by all the threads are performed in some total sequential order. This total order must be consistent with the total order on the actions of each thread.<p>
<a name="28325"></a>
<h2>17.6 Rules about the Interaction of Locks and Variables</h2>
<a name="28326"></a>
Let <i>T</i><em></em> be any thread, let <i>V</i><i></i> be any variable, and let <i>L</i> be any lock. There are certain
constraints on the actions performed by <i>T</i><em></em> with respect to <i>V</i><i></i> and <i>L</i>:
<p><ul><a name="28327"></a>
<li>Between an <i>assign</i> action by <i>T</i><em></em> on <i>V</i><i></i> and a subsequent <i>unlock</i> action by <i>T</i><em></em> on <i>L</i>, a <i>store</i> action by <i>T</i><em></em> on <i>V</i><i></i> must intervene; moreover, the <i>write</i> action corresponding to that <i>store</i> must precede the <i>unlock</i> action, as seen by main memory. (Less formally: if a thread is to perform an <i>unlock</i> action 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="28328"></a>
<li>Between a <i>lock</i> action by <i>T</i><em></em> on <i>L</i> and a subsequent <i>use</i> or <i>store</i> action by <i>T</i><em></em> on a variable <i>V</i><i></i>, an <i>assign</i> or <i>load</i> action on <i>V</i><i></i> must intervene; moreover, if it is a <i>load</i> action, then the <i>read</i> action corresponding to that <i>load</i> must follow the <i>lock</i> action, as seen by main memory. (Less formally: a <i>lock</i> action acts as if it flushes <i>all</i> variables from the thread's working memory; before use they must be assigned or loaded from main memory.)
</ul><a name="28330"></a>
<h2>17.7 Rules for Volatile Variables</h2>
<a name="28331"></a>
If a variable is declared <code>volatile</code>, then additional constraints apply to the actions
of each thread. Let <i>T</i><em></em> be a thread and let <i>V</i><i></i> and <i>W</i> be volatile variables.
<p><ul><a name="28332"></a>
<li>An <i>use</i> action by <i>T</i><em></em> on <i>V</i><i></i> is permitted only if the previous action by <i>T</i><em></em> on <i>V</i><i></i> was <i>load</i>, and a <i>load</i> action by <i>T</i><em></em> on <i>V</i><i></i> is permitted only if the next action by <i>T</i><em></em> on <i>V</i><i></i> is <i>use</i>. The <i>use</i> action is said to be "associated" with the <i>read</i> action that corresponds to the <i>load</i>.
<a name="28333"></a>
<li>A <i>store</i> action by <i>T</i><em></em> on <i>V</i><i></i> is permitted only if the previous action by <i>T</i><em></em> on <i>V</i><i></i> was <i>assign</i>, and an <i>assign</i> action by <i>T</i><em></em> on <i>V</i><i></i> is permitted only if the next action by <i>T</i><em></em> on <i>V</i><i></i> is <i>store</i>. The <i>assign</i> action is said to be "associated" with the <i>write</i> action that corresponds to the <i>store</i>.
<a name="45390"></a>
<li>Let action <i>A</i> be a <i>use</i> or <i>assign</i> by thread <i>T</i><em></em> on variable <i>V</i><i></i>, let action <i>F</i> be the <i>load</i> or <i>store</i> associated with <i>A</i>, and let action <i>P</i> be the <i>read</i> or <i>write</i> of <i>V</i><i></i> that corresponds to <i>F</i>. Similarly, let action <i>B</i> be a <i>use</i> or <i>assign</i> by thread <i>T</i><em></em> on variable  <i>W</i><i></i>, let action <i>G</i> be the <i>load</i> or <i>store</i> associated with <i>B</i>, and let action <i>Q</i> be the <i>read</i> or <i>write</i> of <i>V</i><i></i> that corresponds to <i>G</i><i></i>. If <i>A</i> precedes <i>B</i>, then <i>P</i> must precede <i>Q</i>. (Less formally: actions 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="45376"></a>
<h2>17.8 Prescient Store Actions</h2>
<a name="45377"></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> actions 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
actions out of order by programs that are not properly synchronized.
<p><a name="45378"></a>
Suppose that a <i>store</i> by <i>T</i> of <i>V</i> would follow a particular <i>assign</i> by <i>T</i> of <i>V</i> according to the rules of the previous sections, with no intervening <i>load</i> or <i>assign</i> by <i>T</i> of <i>V</i>. Then that <i>store</i> action would send to the main memory the value that the <i>assign</i> action put into the working memory of thread <i>T</i>. The special rule allows the <i>store</i> action to instead occur before the <i>assign</i> action, if the following restrictions are obeyed:<p>
<ul><a name="45379"></a>
<li>If the <i>store</i> action 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="45380"></a>
<li>No <i>lock</i> action intervenes between the relocated <i>store</i> and the <i>assign</i>.
<a name="45381"></a>
<li>No <i>load</i> of <i>V</i> intervenes between the relocated <i>store</i> and the <i>assign</i>.
<a name="45382"></a>
<li>No other <i>store</i> of <i>V</i> intervenes between the relocated <i>store</i> and the <i>assign</i>.
<a name="45383"></a>
<li>The <i>store</i> action sends to the main memory the value that the <i>assign</i> action will put into the working memory of thread <i>T</i>.
</ul><a name="45384"></a>
This last property inspires us to call such an early <i>store</i> action <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="28341"></a>
<h2>17.9 Discussion</h2>
<a name="28342"></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; synchronized
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="28343"></a>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -