synchronized是一对一的关系,使用synchronized其实是在jvm层面创建了一个monitor对象,然后再去调用monitor对象的wait()方法和notify()方法
condition是一对多的关系,一个lock对象可以创建多个condition对象,从而去调用多个await()方法和signal()方法
public final void await() throws InterruptedException {//如果当前线程是中断状态,抛出中断异常if (Thread.interrupted())throw new InterruptedException();//调用了await方法,说明此节点需要进入condition条件队列//调用addConditionWaiter来入队Node node = addConditionWaiter();//此时node在条件队列是尾节点//释放锁int savedState = fullyRelease(node);//0 在condition队列挂起期间未接收过过中断信号//-1 在condition队列挂起期间接收到中断信号了//1 在condition队列挂起期间为未接收到中断信号,但是迁移到“阻塞队列”之后 接收过中断信号。int interruptMode = 0;//判断当前节点是否被移动到了阻塞队列中//true的话执行唤醒逻辑//false执行挂起逻辑while (!isOnSyncQueue(node)) {//不在阻塞队列,则挂起LockSupport.park(this);if ((interruptMode = checkInterruptWhileWaiting(node)) != 0)break;}//已经移动到阻塞队列中后的唤醒逻辑//下面是各种判断中断的逻辑//如果是在阻塞队列给唤醒,就走这里if (acquireQueued(node, savedState) && interruptMode != THROW_IE)interruptMode = REINTERRUPT;//如果在条件队列中被中断唤醒,就走这里if (Waiter != null) // clean up if cancelledunlinkCancelledWaiters();if (interruptMode != 0)reportInterruptAfterWait(interruptMode);
}
private Node addConditionWaiter() {//拿到全局变量尾节点,保存到t中Node t = lastWaiter;//t != null 说明条件队列是存在的 并且状态不为condition 说明当前节点发生了中断//执行清除条件队列中取消状态的节点逻辑if (t != null && t.waitStatus != Node.CONDITION) {unlinkCancelledWaiters();//更新尾节点引用,上面的清除方法可能会改变尾节点t = lastWaiter;}//如果当前节点不是中断节点,则将状态设置为condition,并且执行入队操作,并返回尾节点Node node = new Node(Thread.currentThread(), Node.CONDITION);if (t == null)firstWaiter = Waiter = node;lastWaiter = node;return node;
}
//清除中断节点逻辑
//如果判断条件队列尾节点状态不为condition,才会进入到这个方法
private void unlinkCancelledWaiters() {Node t = firstWaiter;//表示当前链表中,上一个状态为condition的节点Node trail = null;//循环迭代将所有非condition状态节点出队while (t != null) {Node next = t.nextWaiter;if (t.waitStatus != Node.CONDITION) {t.nextWaiter = null;if (trail == null)firstWaiter = Waiter = next;if (next == null)lastWaiter = trail;}elsetrail = t;t = next;}
}
//释放锁逻辑
//成功返回锁数量,失败抛出异常,并且修改当前入队节点状态为cancelled
final int fullyRelease(Node node) {boolean failed = true;try {int savedState = getState();if (release(savedState)) {failed = false;return savedState;} else {throw new IllegalMonitorStateException();}} finally {if (failed)node.waitStatus = Node.CANCELLED;}
}
//状态为condition,返回false
//状态为0,且prev不为null && next不为null 返回true
//状态为0,prev为null,返回false
//状态为0,prev不为null,但是next为null,说明是尾节点,去遍历,遍历成功返回true
//状态为cancell,prev一定是null,返回false
final boolean isOnSyncQueue(Node node) {//如果当前节点状态为condition,说明一定在条件队列中//如果当前节点状态不为condition,要么是0 要是是 -1//所有去判断前置节点是否为空,为空说明当前节点只是被修改了状态,但是还未完全被迁移到阻塞队列中//取消状态节点肯定不会被signal方法迁移到阻塞队列中if (node.waitStatus == Node.CONDITION || node.prev == null)return false;//只有状态不为condition且前置节点不为空的节点才会到这里判断if ( != null) // If has successor, it must be on queuereturn true;return findNodeFromTail(node);
}
public final void signal() {//非独占锁模式,抛出异常if (!isHeldExclusively())throw new IllegalMonitorStateException();//拿到条件队列中的第一个节点,然后去调用doSignal方法Node first = firstWaiter;if (first != null)doSignal(first);
}
private void doSignal(Node first) {do {//移动节点if ( (firstWaiter = Waiter) == null)lastWaiter = null;//出队,所有将下一个节点的指针指向空Waiter = null;//while里面做迁移到阻塞队列的工作} while (!transferForSignal(first) &&(first = firstWaiter) != null);
}
final boolean transferForSignal(Node node) {//如果节点状态时condition,则会修改为0if (!compareAndSetWaitStatus(node, Node.CONDITION, 0))return false;//加入阻塞队列Node p = enq(node);//拿到当前节点前置节点的状态int ws = p.waitStatus;//如果前置节点状态为0或者为-1,就修改为signalif (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL))LockSupport.unpark(node.thread);return true;
}
本文发布于:2024-02-01 23:46:26,感谢您对本站的认可!
本文链接:https://www.4u4v.net/it/170680729439948.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
留言与评论(共有 0 条评论) |