Java AbstractQueuedSynchronizer 中的 Node 节点

AbstractQueuedSynchronizer 中的 Node 节点,等待队列中的单个节点对象;

AbstractQueuedSynchronizer#Node.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
/* 等待队列中的单个节点对象,每个节点都有status字段,用于表示线程是否应该block;
* 一个节点被signal唤醒,当它的前一个节点release的时候。
* A node is signalled when its predecessor releases.
* 队列里面的每一个节点都作为一个等待线程的monitor(监视器),
* status属性并不保证线程是否获取到锁,如果线程是queue中的第一个则会尝试获取锁
* 但是是第一个线程并不保证能一定能获取锁,仅仅是给予竞争获取锁的权利。
* 所以当前released的竞争线程可能需要重新wait。
* enqueue: 将节点设置为tail
* dequeue: 重新设置head节点
* <pre>
* +------+ prev +-----+ +-----+
* head | | <---- | | <---- | | tail
* +------+ +-----+ +-----+
* </pre>
* 往队列中插入一个节点只需要操作tail节点,同样的,出列只需要操作head节点。
* dequeuing involves(涉及) only updating the "head".
* 然而,设置头节点的时候,要复杂些,因为需要找到合适的继任者,因为head的下一节点
* 可能已经cancel因为timeout或者interrupt。
*
* We also use "next" links to implement blocking mechanics.
* The thread id for each node is kept in its own node, so a
* predecessor signals the next node to wake up by traversing
* next link to determine which thread it is.
* 我们还使用“next”链接来实现阻塞机制。每个节点的线程ID保存在自己的节点中,
* 所以一个前任通过下一个链接来通知下一个节点唤醒它,以确定它是哪个线程
*
* CLH queues need a dummy header node to get started. But
* we don't create them on construction, because it would be wasted
* effort if there is never contention. Instead, the node
* is constructed and head and tail pointers are set upon first
* contention.
* 队列需要一个假的head节点,但是我们不会在构造器中创建它们,因为可能从来不会有
* 争夺发生,取而代之的是,head和tail节点会在第一次争夺资源的时候被实例化
*
* Threads waiting on Conditions use the same nodes, but
* use an additional link. Conditions only need to link nodes
* in simple (non-concurrent) linked queues because they are
* only accessed when exclusively held. Upon await, a node is
* inserted into a condition queue. Upon signal, the node is
* transferred to the main queue. A special value of status
* field is used to mark which queue a node is on.
*
* 等待条件的线程使用相同的节点,但使用另一个链接。条件只需要链接简单(非并发)
* 链接队列中的节点,因为只有在独占时才访问它们。在等待之后,将插入一个节点到条件队列中。
* 收到释放信号后,节点被转移到主队列。用一个特殊的status值来表示node在哪一个队列中。
*/
static final class Node {
/** 表示shared mode的常量node节点 */
static final Node SHARED = new Node();
/** 表示独享模式的常量节点 */
static final Node EXCLUSIVE = null;
/** waitStatus value to indicate thread has cancelled */
static final int CANCELLED = 1;
/** waitStatus value to indicate successor's thread needs unparking */
static final int SIGNAL = -1;
/** waitStatus value to indicate thread is waiting on condition
* 用于Conditoin的waitStatus状态
*/
static final int CONDITION = -2;
/**
* waitStatus value to indicate the next acquireShared should
* unconditionally propagate(传播)
*/
static final int PROPAGATE = -3;
/**
* Status field, taking on only the values:
* SIGNAL: The successor of this node is (or will soon be)
* blocked (via park), so the current node must
* unpark its successor when it releases or
* cancels. To avoid races, acquire methods must
* first indicate they need a signal,
* then retry the atomic acquire, and then,
* on failure, block.
* node的继承者已经(或者即将成为)block,所以当前节点必须unpark
* 自己的继任者当它release或者cancel的时候,为了避免竞争,
* acquire方法必须先设置waitStatus为SINGAL,然后再次acquire,
* 最后,如果失败了,则block线程;
*
* CANCELLED: This node is cancelled due to timeout or interrupt.
* Nodes never leave this state. In particular,
* a thread with cancelled node never again blocks.
* 节点被取消(由于timeout或者interrupt),被取消的线程,
* 不会再次block;
*
* CONDITION: This node is currently on a condition queue.
* It will not be used as a sync queue node
* until transferred, at which time the status
* will be set to 0. (Use of this value here has
* nothing to do with the other uses of the
* field, but simplifies mechanics.)
* 表明node在condition队列中,节点不会被当作同步节点直到节点
* 被transferred,此时,waitStatus将被置为0
*
* PROPAGATE: A releaseShared should be propagated to other
* nodes. This is set (for head node only) in
* doReleaseShared to ensure propagation
* continues, even if other operations have
* since intervened(加入).
* 表示releaseShared应该被传播到其它节点,在doReleaseShared
* 方法中被设置(只能是设置给head节点)
*
* 0: None of the above
*
* 非负的值,表示节点不需要等待signal
* Non-negative values mean that a node doesn't need to
* signal. So, most code doesn't need to check for particular
* values, just for sign.
*
* The field is initialized to 0 for normal sync nodes;
* CONDITION for condition nodes. It is modified using CAS
* (or when possible, unconditional volatile writes).
*/
volatile int waitStatus;
/**
* 链接到前一个Node节点,在入列的时候被赋值,或者出列的时候,当前一个节点已经
* 被取消了,继续向前查找未取消的节点,直到head节点(head节点是不会取消的,
* 会一直存在)
* 只有在成功acquire的时候,节点才会成为head节点;
* A node becomes head only as a result of successful acquire.
* 已经取消掉的线程,永远不会acquire成功;
*/
volatile Node prev;
/**
* 指向前一个节点,当前节点的thread在unpark(release)的时候,需要用到
* Link to the successor node that the current node/thread
* unparks upon release. 入列的时候指定, 当处理取已经取消的前任节点时
* 会自动调整,当出列的时候,清空next节点。入列操作不会指定节点的next属性
* 直到节点真正被添加。所以next为空并不一定意味节点是队列中的最后一个节点
* The enq operation does not assign next field of a predecessor
* until after attachment,so seeing a null next field does not
* necessarily mean that node is at end of queue.
* 然而,如果next属性为空,我们可以扫描tail节点的prev属性
* However, if a next field appears to be null, we can scan prev's
* from the tail to double-check.
* cancelled的节点的next属性被设置为指向节点本身,而不是指向null.
*/
volatile Node next;
/** 添加该节点的Thread,构造函数中被初始化,使用完之后清空 */
volatile Thread thread;
/**
* 指导向下一个等待Condition状态的节点,或者是特定的SHARED.
* Link to next node waiting on condition, or the special value SHARED.
* 因为condition队列仅在独享模式使用,所以我们只需要一个简单的队列把节点串起来。
* 因为conditions只能是独享模式下使用,所以我们定义一个特殊的值来表示。
*/
Node nextWaiter;
final boolean isShared() {
return nextWaiter == SHARED;
}
/**
* 返回前一个节点
* @return the predecessor of this node
*/
final Node predecessor() throws NullPointerException {
Node p = prev;
if (p == null)
throw new NullPointerException();
else
return p;
}
Node() { // Used to establish(建立) initial head or SHARED marker
}
// addWaiter中使用,node为当前节点的nextWaiter
Node(Thread thread, Node mode) { // Used by addWaiter
this.nextWaiter = mode;
this.thread = thread;
}
// 在Conditon中使用,直接指定当前的waitStatus
Node(Thread thread, int waitStatus) { // Used by Condition
this.waitStatus = waitStatus;
this.thread = thread;
}
}