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

📄 17.doc.html

📁 java语言规范
💻 HTML
📖 第 1 页 / 共 4 页
字号:
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> action, if necessary, and will copy back to main memory the value most recently assigned to that variable before the <i>unlock</i> action. 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="28344"></a>
The rules for <code>volatile</code> variables effectively require that main memory be touched exactly once for each <i>use</i> or <i>assign</i> of a <code>volatile</code> variable by a thread, and that main memory be touched in exactly the order dictated by the thread execution semantics. However, such memory actions are not ordered with respect to <i>read</i> and <i>write</i> actions on nonvolatile variables.<p>
<a name="28345"></a>
<h2>17.10    Example: Possible Swap</h2>
<a name="28346"></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><a name="28347"></a>
class Sample {
<a name="28348"></a>	int a = 1, b = 2;
<a name="28349"></a>	void hither() {
<a name="28350"></a>		a = b;
<a name="28351"></a>	}
<a name="28352"></a>	void yon() {
<a name="28353"></a>		b = a;
<a name="28354"></a>	}
<a name="28355"></a>}
</pre><a name="28356"></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="28357"></a>
Let us consider the thread that calls <code>hither</code>. According to the rules, this thread must perform an <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="28358"></a>
Now, the first action 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> action, so a <i>load</i> of <code>b</code> is required. This <i>load</i> action by the thread in turn requires a preceding <i>read</i> action for <code>b</code> by the main memory.<p>
<a name="28359"></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> action in turn requires a following <i>write</i> action for <code>a</code> by the main memory.<p>
<a name="28360"></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="28388"></a>
The total set of actions may be pictured as follows:<img src="17.doc.anc.gif"><p>
<a name="29084"></a>
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="28389"></a>
In what order may the actions 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> actions are to occur, there are three possible orderings in which the main memory might legitimately perform its actions. 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 actions and the resulting states are as follows:<p>
<ul><a name="28390"></a>
<li><i>write</i> <code>a</code><img src="chars/arrwrite.gif"><i>read</i> <code>a</code>, <i>read</i> <code>b</code><img src="chars/arrwrite.gif"><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="29157"></a>
<li><i>read</i> <code>a</code><img src="chars/arrwrite.gif"><i>write</i> <code>a</code>, <i>write</i> <code>b</code><img src="chars/arrwrite.gif"><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="28391"></a>
<li><i>read</i> <code>a</code><img src="chars/arrwrite.gif"><i>write</i> <code>a</code>, <i>read</i> <code>b</code><img src="chars/arrwrite.gif"><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="29137"></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="29184"></a>
Of course, an implementation might also choose not to perform the <i>store</i> and <i>write</i> actions, or only one of the two pairs, leading to yet other possible results.<p>
<a name="29185"></a>
Now suppose that we modify the example to use <code>synchronized</code> methods:<p>
<pre><a name="28399"></a>
class SynchSample {
<a name="28400"></a>	int a = 1, b = 2;
<a name="28401"></a>	synchronized void hither() {
<a name="28402"></a>		a = b;
<a name="28403"></a>	}
<a name="28404"></a>	synchronized void yon() {
<a name="28405"></a>		b = a;
<a name="28406"></a>	}
<a name="28407"></a>}
</pre><a name="28408"></a>
Let us again consider the thread that calls <code>hither</code>. According to the rules, this 
thread must perform a <i>lock</i> action (on the class 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> action on the class 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="28409"></a>
As before, a <i>load</i> of <code>b</code> is required, which in turn requires a preceding <i>read</i> action for <code>b</code> by the main memory. Because the <i>load</i> follows the <i>lock</i> action, the corresponding <i>read</i> must also follow the <i>lock</i> action.<p>
<a name="28410"></a>
Because an <i>unlock</i> action follows the <i>assign</i> of <code>a</code>, a <i>store</i> action on <code>a</code> is mandatory, which in turn requires a following <i>write</i> action for <code>a</code> by the main memory. The <i>write</i> must precede the <i>unlock</i> action.<p>
<a name="28411"></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="28451"></a>
The total set of actions may be pictured as follows:<img src="17.doc.anc1.gif"><p>
<a name="29170"></a>
The <i>lock</i> and <i>unlock</i> actions provide further constraints on the order of actions by the main memory; the <i>lock</i> action by one thread cannot occur between the <i>lock</i> and <i>unlock</i> actions of the other thread. Moreover, the <i>unlock</i> actions require that the <i>store</i> and <i>write</i> actions occur. It follows that only two sequences are possible:<p>
<ul><a name="29161"></a>
<li><i>write</i> <code>a</code><img src="chars/arrwrite.gif"><i>read</i> <code>a</code>, <i>read</i> <code>b</code><img src="chars/arrwrite.gif"><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="29162"></a>
<li><i>read</i> <code>a</code><img src="chars/arrwrite.gif"><i>write</i> <code>a</code>, <i>write</i> <code>b</code><img src="chars/arrwrite.gif"><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>)
</ul><a name="28455"></a>
While the resulting state is timing-dependent, it can be seen that the two threads 
will necessarily agree on the values of <code>a</code> and <code>b</code>.
<p><a name="29188"></a>
<h2>17.11    Example: Out-of-Order Writes</h2>
<a name="29191"></a>
This example is similar to that in the preceding section, except that one method 
assigns to both variables and the other method reads both variables. Consider a 
class that has class variables <code>a</code> and <code>b</code> and methods <code>to</code> and <code>fro</code>:
<p><pre><a name="29192"></a>
class Simple {
<a name="29193"></a>	int a = 1, b = 2;
<a name="29194"></a>	void to() {
<a name="29195"></a>		a = 3;
<a name="29261"></a>		b = 4;
<a name="29196"></a>	}
<a name="29197"></a>	void fro() {
<a name="29265"></a>		System.out.println("a= " + a + ", b=" + b);
<a name="29276"></a>	}
<a name="29200"></a>}
</pre><a name="29201"></a>
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="29202"></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="29315"></a>
Now suppose that <code>to</code> is <code>synchronized</code> but <code>fro</code> is not:<p>
<pre><a name="29318"></a>
class SynchSimple {
<a name="29319"></a>	int a = 1, b = 2;
<a name="29320"></a>	synchronized void to() {

⌨️ 快捷键说明

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