* 一个节点被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 {
static final Node SHARED = new Node();
static final Node EXCLUSIVE = null;
static final int CANCELLED = 1;
static final int SIGNAL = -1;
* 用于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;
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() {
}
Node(Thread thread, Node mode) {
this.nextWaiter = mode;
this.thread = thread;
}
Node(Thread thread, int waitStatus) {
this.waitStatus = waitStatus;
this.thread = thread;
}
}