admin管理员组文章数量:1550528
笔下天地宽
接着上一章继续说,上次我们讲到了一个关键字段waitStatus,这个字段对队列的管理很重要。我们下面来详细说一下。上一章也说了,
每个队列的节点都有自己的状态,方便更好的利用资源和管理队列,Node节点其实是对等待线程的一个装,其中包含了线程的信息以及等待状态 ,如是否被阻塞、是否等待、是否需要删除等等,这个状态的控制就是交给waitStatus的,下面先说下waitStatus。
waitStatuswaitStatus共有5个值,CANCELLED、SIGNAL、CONDITION、PROPAGATE、0。看下AQS里面的定义。
/** 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 */
static final int CONDITION = -2;
/**
* waitStatus value to indicate the next acquireShared should
* unconditionally propagate
*/
static final int PROPAGATE = -3;
下面说明下:
CANCELLED(1):表示当前节点已经取消调度,当超时或者中断会触发变更为此状态,进入该状态后节点将不会再变化。
SIGNAL(-1) :表示后继节点在等待当前节点唤醒。后继节点入队时,会将前继节点状态更新为SINGAL。
CONDITION(-2): 表示节点等待在Condition上(条件队列,后面再说),当其他线程调用了Condition的signal()方法后,CONDITION状态的节点将从等待移到阻塞队列中,等待获取资源。
PROPAGATE(-3): 表示共享模式下(实现共享锁),前继节点不仅会唤醒它的后继节点,同时也可能唤醒后继节点的后继节点。
0:新节点入队时的默认状态。
可以看到节点处于有效的等待状态的话都是负值,而正值对应的是节点被取消,所以很多地方用大于0或者小于0来判断节点状态是否正常。下面从百度找了一张图,大家可以先看下。
下面继续说代码,上一章讲到了shouldParkAfterFailAcquire这个方法,下面来看下。
private static boolean shouldParkAfterFailedAcquire(Node pred, Node node) {
int ws = pred.waitStatus;
if (ws == Node.SIGNAL)
//直接返回
return true;
if (ws > 0) {
// 大于0的状态只有1,表示这个线程的调度(抢占资源操作)取消了,那就把这个线程移除掉,放着也没用了
do {
node.prev = pred = pred.prev;
} while (pred.waitStatus > 0);
pred.next = node;
} else {
// 否则就把当前线程的状态修改为SIGNAL
compareAndSetWaitStatus(pred, ws, Node.SIGNAL);
}
return false;
}
下面接着看,
private final boolean parkAndCheckInterrupt() {
LockSupport.park(this); //当前线程等待
return Thread.interrupted(); 返回当前现在interrupt
}
这个不多说了,看下面一个方法
cancelAcquire。
private void cancelAcquire(Node node) { //出现异常,取消获取锁操作
// 如果当前节点不存在,当然也就不用管了
if (node == null)
return;
node.thread = null;
// 跳过取消的前置节点
Node pred = node.prev;
while (pred.waitStatus > 0) //大于0 ,代表是取消
node.prev = pred = pred.prev;
Node predNext = pred.next;
node.waitStatus = Node.CANCELLED;
// 如果是尾节点,直接删除
if (node == tail && compareAndSetTail(node, pred)) {
compareAndSetNext(pred, predNext, null);
} else {
int ws;
// 节点状态判断重新设置,只要是节点的操作,就不多说了
if (pred != head &&
((ws = pred.waitStatus) == Node.SIGNAL ||
(ws <= 0 && compareAndSetWaitStatus(pred, ws, Node.SIGNAL))) &&
pred.thread != null) {
Node next = node.next;
if (next != null && next.waitStatus <= 0)
compareAndSetNext(pred, predNext, next);
} else {
unparkSuccessor(node); //解除等待
}
node.next = node; // help GC
}
}
先说到这里吧,下面再说释放锁吧!谢谢观看。
No sacifice,no victory!!
本文标签: 队列线程JavaReentrantLock
版权声明:本文标题:谈谈对java线程的理解(五)--------ReentrantLock之阻塞队列 内容由热心网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:https://m.elefans.com/dianzi/1727247156a1104766.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论