📄 threads.doc.html
字号:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2//EN">
<html>
<head>
<title>VM Spec Threads and Locks</title>
</head>
<body BGCOLOR=#eeeeff text=#000000 LINK=#0000ff VLINK=#000077 ALINK=#ff0000>
<table width=100%><tr>
<td><a href="VMSpecTOC.doc.html">Contents</a> | <a href="Compiling.doc.html">Prev</a> | <a href="Quick.doc.html">Next</a> | <a href="Lindholm.INDEX.html">Index</a></td><td align=right><i><i>The Java<sup><font size=-2>TM</font></sup> Virtual Machine Specification</i></i></td>
</tr></table>
<hr><br>
<a name="21293"></a>
<p><strong>CHAPTER 8 </strong></p>
<a name="21294"></a>
<h1>Threads and Locks</h1>
<hr><p>
<a name="22138"></a>
This chapter details the low-level actions that may be used to explain the interaction of Java Virtual Machine threads with a shared main memory. It has been
reprinted with minimal changes from <i>The Java Language Specification</i>, by James
Gosling, Bill Joy, and Guy Steele.
<p><a name="22197"></a>
<hr><h2>8.1 Terminology and Framework</h2>
<a name="22198"></a>
A <i>variable</i> is any location within a Java program that may be stored into. This
includes not only class variables and instance variables, but also components of
arrays. Variables are kept in a <i>main memory</i> that is shared by all threads. Because
it is impossible for one thread to access parameters or local variables of another
thread, it does not matter whether parameters and local variables are thought of as
residing in the shared main memory or in the working memory of the thread that
owns them.
<p><a name="22199"></a>
Every thread has a <i>working memory</i> in which it keeps its own <i>working copy</i> of variables that it must use or assign. As the thread executes a Java program, it operates on these working copies. The main memory contains the <i>master copy</i> of every variable. There are rules about when a thread is permitted or required to transfer the contents of its working copy of a variable into the master copy or vice versa.<p>
<a name="22200"></a>
The main memory also contains <i>locks</i>; there is one lock associated with each object. Threads may compete to acquire a lock.<p>
<a name="22201"></a>
For the purposes of this chapter, the verbs <i>use</i>, <i>assign</i>, <i>load</i>, <i>store</i>, <i>lock</i>, and <i>unlock</i> name actions that a thread can perform. The verbs <i>read</i>, <i>write</i>, <i>lock</i>, and <i>unlock</i> name actions that the main memory subsystem can perform. Each of these operations is atomic (indivisible). <p>
<a name="22202"></a>
A <i>use</i> or <i>assign</i> operation is a tightly coupled interaction between a thread's execution engine and the thread's working memory. A <i>lock</i> or <i>unlock</i> operation is a tightly coupled interaction between a thread's execution engine and the main memory. But the transfer of data between the main memory and a thread's working memory is loosely coupled. When data is copied from the main memory to a working memory, two actions must occur: a <i>read</i> operation performed by the main memory, followed some time later by a corresponding <i>load</i> operation performed by the working memory. When data is copied from a working memory to the main memory, two actions must occur: a <i>store</i> operation performed by the working memory, followed some time later by a corresponding <i>write</i> operation performed by the main memory. There may be some transit time between main memory and a working memory, and the transit time may be different for each transaction; thus, operations initiated by a thread on different variables may viewed by another thread as occurring in a different order. For each variable, however, the operations in main memory on behalf of any one thread are performed in the same order as the corresponding operations by that thread. (This is explained in greater detail later.)<p>
<a name="22203"></a>
A single Java thread issues a stream of <i>use</i>, <i>assign</i>, <i>lock</i>, and <i>unlock</i> operations as dictated by the semantics of the Java program it is executing. The underlying Java implementation is then required additionally to perform appropriate <i>load</i>, <i>store</i>, <i>read</i>, and <i>write</i> operations so as to obey a certain set of constraints, explained later. If the Java implementation correctly follows these rules and the Java application programmer follows certain other rules of programming, then data can be reliably transferred between threads through shared variables. The rules are designed to be "tight" enough to make this possible, but "loose" enough to allow hardware and software designers considerable freedom to improve speed and throughput through such mechanisms as registers, queues, and caches.<p>
<a name="22204"></a>
Here are the detailed definitions of each of the operations:<p>
<ul><a name="22205"></a>
<li>A <i>use</i> action (by a thread) transfers the contents of the thread's working copy of a variable to the thread's execution engine. This action is performed whenever a thread executes a virtual machine instruction that uses the value of a variable.
<a name="22206"></a>
<li>An <i>assign</i> action (by a thread) transfers a value from the thread's execution engine into the thread's working copy of a variable. This action is performed whenever a thread executes a virtual machine instruction that assigns to a variable.
<a name="22207"></a>
<li>A <i>read</i> action (by the main memory) transmits the contents of the master copy of a variable to a thread's working memory for use by a later <i>load</i> operation.
<a name="22208"></a>
<li>A <i>load </i>action (by a thread) puts a value transmitted from main memory by a <i>read</i> action into the thread's working copy of a variable.
<a name="22209"></a>
<li>A <i>store </i>action (by a thread) transmits the contents of the thread's working copy of a variable to main memory for use by a later <i>write</i> operation.
<a name="22210"></a>
<li>A <i>write</i> action (by the main memory) puts a value transmitted from the thread's working memory by a <i>store</i> action into the master copy of a variable in main memory.
<a name="22211"></a>
<li>A <i>lock</i> action (by a thread tightly synchronized with main memory) causes a thread to acquire one claim on a particular lock.
<a name="22212"></a>
<li>An <i>unlock</i> action (by a thread tightly synchronized with main memory) causes a thread to release one claim on a particular lock.
</ul><a name="22213"></a>
Thus, the interaction of a thread with a variable over time consists of a sequence of <i>use</i>, <i>assign</i>, <i>load</i>, and <i>store</i> operations. Main memory performs a <i>read</i> operation for every <i>load</i> and a <i>write</i> operation for every <i>store</i>. A thread's interactions with a lock over time consist of a sequence of <i>lock</i> and <i>unlock</i> operations. All the globally visible behavior of a thread thus comprises all the thread's operations on variables and locks.<p>
<a name="22214"></a>
<hr><h2>8.2 Execution Order and Consistency</h2>
<a name="22215"></a>
The rules of execution order constrain the order in which certain events may
occur. There are four general constraints on the relationships among actions:
<p><ul><a name="22216"></a>
<li>The actions performed by any one thread are totally ordered; that is, for any two actions performed by a thread, one action precedes the other.
<a name="22217"></a>
<li>The actions performed by the main memory for any one variable are totally ordered; that is, for any two actions performed by the main memory on the same variable, one action precedes the other.
<a name="22218"></a>
<li>The actions performed by the main memory for any one lock are totally ordered; that is, for any two actions performed by the main memory on the same lock, one action precedes the other.
<a name="22219"></a>
<li>It is not permitted for an action to follow itself.
</ul><a name="22220"></a>
The last rule may seem trivial, but it does need to be stated separately and explicitly for completeness. Without it, it would be possible to propose a set of actions
by two or more threads and precedence relationships among the actions that
would satisfy all the other rules but would require an action to follow itself.
<p><a name="22221"></a>
Threads do not interact directly; they communicate only through the shared main memory. The relationships between the actions of a thread and the actions of main memory are constrained in three ways: <p>
<ul><a name="22222"></a>
<li>Each <i>lock</i> or <i>unlock</i> action is performed jointly by some thread and the main memory.
<a name="22223"></a>
<li>Each <i>load</i> action by a thread is uniquely paired with a <i>read</i> action by the main memory such that the <i>load</i> action follows the <i>read</i> action.
<a name="22224"></a>
<li>Each <i>store</i> action by a thread is uniquely paired with a <i>write</i> action by the main memory such that the <i>write</i> action follows the <i>store</i> action.
</ul><a name="22225"></a>
Most of the rules in the following sections further constrain the order in which certain actions take place. A rule may state that one action must precede or follow some other action. Note that this relationship is transitive: if action A must precede action B, and B must precede C, then A must precede C. The programmer must remember that these rules are the <i>only</i> constraints on the ordering of actions; if no rule or combination of rules implies that action A must precede action B, then a Java implementation is free to perform action B before action A, or to perform action B concurrently with action A. This freedom can be the key to good performance. Conversely, an implementation is not required to take advantage of all the freedoms given it.<p>
<a name="22226"></a>
In the rules that follow, the phrasing "B must intervene between A and C" means that action B must follow action A and precede action C.<p>
<a name="22227"></a>
<hr><h2>8.3 Rules About Variables</h2>
<a name="22228"></a>
Let T<em></em> be a thread and V<i></i> be a variable. There are certain constraints on the operations performed by T<em></em> with respect to V<i></i>:
<p><ul><a name="22229"></a>
<li>A <i>use</i> or <i>assign</i> by T<em></em> of V<i></i> is permitted only when dictated by execution by T<em></em> of the Java program according to the standard Java execution model. For example, an occurrence of V<i></i> as an operand of the <code>+</code> operator requires that a single <i>use</i> operation occur on V<i></i>; an occurrence of V<i></i> as the left-hand operand of the assignment operator <code>=</code> requires that a single <i>assign</i> operation 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 T<em></em> to perform a required <i>use</i> as its next action, it may be necessary for T<em></em> to perform a <i>load </i>first in order to make progress.
<a name="22230"></a>
<li>A <i>store</i> operation by T<em></em> on V<i></i> must intervene between an <i>assign</i> by T<em></em> of V<i></i> and a subsequent <i>load</i> by T<em></em> of V<i></i>. (Less formally: a thread is not permitted to lose the most recent assign.)
<a name="22231"></a>
<li>An <i>assign</i> operation by T<em></em> on V<i></i> must intervene between a <i>load</i> or <i>store</i> by T<em></em> of V<i></i> and a subsequent <i>store</i> by T<em></em> of V<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="22232"></a>
<li>After a thread is created, it must perform an <i>assign</i> or <i>load</i> operation on a variable before performing a <i>use</i> or <i>store</i> operation on that variable. (Less formally: a new thread starts with an empty working memory.)
<a name="22233"></a>
<li>After a variable is created, every thread must perform an <i>assign</i> or <i>load</i> operation on that variable before performing a <i>use</i> or <i>store</i> operation 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="22234"></a>
Provided that all the constraints in <a href="Threads.doc.html#22227">§8.3</a>, <a href="Threads.doc.html#22253">§8.6</a>, and <a href="Threads.doc.html#22258">§8.7</a> are obeyed, a <i>load</i> or <i>store</i> operation may be issued at any time by any thread on any variable, at the whim of the implementation.<p>
<a name="22235"></a>
There are also certain constraints on the <i>read</i> and <i>write</i> operations performed by main memory:<p>
<ul><a name="22236"></a>
<li>For every <i>load</i> operation performed by any thread <em>T</em> on its working copy of a variable V<i></i>, there must be a corresponding preceding <i>read</i> operation by the main memory on the master copy of V<i></i>, and the <i>load</i> operation must put into the working copy the data transmitted by the corresponding <i>read</i> operation.
<a name="22237"></a>
<li>For every <i>store</i> operation performed by any thread <em>T</em> on its working copy of a variable V<i></i>, there must be a corresponding following <i>write</i> operation by the main memory on the master copy of V<i></i>, and the <i>write</i> operation must put into the master copy the data transmitted by the corresponding <i>store</i> operation.
<a name="24391"></a>
<li>Let action A be a <i>load</i> or <i>store</i> by thread <em>T</em> on variable V<i></i>, and let action P be the corresponding <i>read</i> or <i>write</i> by the main memory on variable V<i></i>. Similarly, let action B<i> </i>be some other <i>load</i> or <i>store</i> by thread <em>T</em> on that same variable V<i></i>, and let action Q be the corresponding <i>read</i> or <i>write</i> by the main memory on variable V<i></i>. If A precedes B, then P must precede Q. (Less formally: operations 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="24392"></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="Threads.doc.html#22258">(§8.7)</a>.
<p><a name="22244"></a>
<hr><h2>8.4 Nonatomic Treatment of Double and Long Variables</h2>
<a name="22245"></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> operations it is treated as if it were two variables of
32 bits each: wherever the rules require one of these operations, two such operations 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 and the order
of the operations on the halves of the variables are not defined by <i>The Java Language Specification</i>.
<p><a name="22246"></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> operations that may be separated in time, with other operations 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="22247"></a>
An implementation is free to implement <i>load</i>, <i>store</i>, <i>read</i>, and <i>write</i> operations for <code>double</code> and <code>long</code> values as atomic 64-bit operations; 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="22248"></a>
<hr><h2>8.5 Rules About Locks</h2>
<a name="22249"></a>
Let T<em></em> be a thread and L<i></i> be a lock. There are certain constraints on the operations
performed by T<em></em> with respect to L<i></i>:
<p><ul><a name="22250"></a>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -