Condition实现原理
来源:互联网 发布:mac怎么看电池循环 编辑:程序博客网 时间:2024/06/07 03:24
Condition可以阻塞或唤醒线程,配合lock使用达到类似于wait()和notify()的效果。本文主要根据jdk源码讲解condition的实现原理。
Condition是一个接口,首先看看接口中定义的方法列表
public interface Condition { void await() throws InterruptedException;//类似于wait(),可以响应中断 void awaitUninterruptibly();//不响应中断的等待 long awaitNanos(long nanosTimeout) throws InterruptedException;//等待指定时间(单位是纳秒),在接到信号、被中断或到达指定等待时间之前一直处于等待状态。方法返回被唤醒后的剩余等待时间,若返回值小于等于0则代表此次等待超时。boolean await(long time, TimeUnit unit) throws InterruptedException;//指定时间到达前结束等待返回true,否则返回falseboolean awaitUntil(Date deadline) throws InterruptedException;//指定日期到达前被唤醒返回true,否则返回falsevoid signal();//唤醒一个等待中的线程,类似于notify()void signalAll();//唤醒所有等待中的线程,类似于notifyAll()}
以AbstractQueuedSynchronizer,看看Condition中几个主要方法的实现原理。
首先看一下await()
public final void await() throws InterruptedException { if (Thread.interrupted()) throw new InterruptedException(); Node node = addConditionWaiter(); int savedState = fullyRelease(node); int interruptMode = 0; while (!isOnSyncQueue(node)) { LockSupport.park(this); if ((interruptMode = checkInterruptWhileWaiting(node)) != 0) break; } if (acquireQueued(node, savedState) && interruptMode != THROW_IE) interruptMode = REINTERRUPT; if (node.nextWaiter != null) // clean up if cancelled unlinkCancelledWaiters(); if (interruptMode != 0) reportInterruptAfterWait(interruptMode); }
一步一步分析,先看addConditionWaiter()
private Node addConditionWaiter() { Node t = lastWaiter; // If lastWaiter is cancelled, clean out. if (t != null && t.waitStatus != Node.CONDITION) { unlinkCancelledWaiters(); t = lastWaiter; } Node node = new Node(Thread.currentThread(), Node.CONDITION); if (t == null) firstWaiter = node; else t.nextWaiter = node; lastWaiter = node; return node; }
代码目的很明显了,将当前线程加入到等待节点中。在看看下一步fullyRelease
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; } }
可以看到这部分代码是释放当前线程所持有的锁,在release()方法中同时会唤醒等待锁的线程,这个在上一篇将lock的文章分析过,这里就不阐述了。
继续往下,将执行这段循环
while (!isOnSyncQueue(node)) { LockSupport.park(this); if ((interruptMode = checkInterruptWhileWaiting(node)) != 0) break; }
看一看其中的isOnSyncQueue方法
final boolean isOnSyncQueue(Node node) { if (node.waitStatus == Node.CONDITION || node.prev == null) return false; if (node.next != null) // If has successor, it must be on queue return true; return findNodeFromTail(node); } private boolean findNodeFromTail(Node node) { Node t = tail; for (;;) { if (t == node) return true; if (t == null) return false; t = t.prev; } }
这段就是判断是否节点已经加入了AbstractQueuedSynchronizer的队列中。直到节点从队列中移除后才能成功挂起。
接下来是从挂起状态被唤醒后重新获取锁和一系列状态更新的操作。
if (acquireQueued(node, savedState) && interruptMode != THROW_IE) interruptMode = REINTERRUPT; if (node.nextWaiter != null) // clean up if cancelled unlinkCancelledWaiters(); if (interruptMode != 0) reportInterruptAfterWait(interruptMode);
由此便完成了await过程。下面我们来看看signal
public final void signal() { if (!isHeldExclusively()) throw new IllegalMonitorStateException(); Node first = firstWaiter; if (first != null) doSignal(first); } private void doSignal(Node first) { do { if ( (firstWaiter = first.nextWaiter) == null) lastWaiter = null; first.nextWaiter = null; } while (!transferForSignal(first) && (first = firstWaiter) != null); }
通过transferForSignal方法将头节点唤醒,也使用了cas操作保证一致性。
final boolean transferForSignal(Node node) { if (!compareAndSetWaitStatus(node, Node.CONDITION, 0)) return false; Node p = enq(node); int ws = p.waitStatus; if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL)) LockSupport.unpark(node.thread); return true; }
唤醒后将使下一个节点成为头节点。至此signal过程结束。
下面看看signalAll
public final void signalAll() { if (!isHeldExclusively()) throw new IllegalMonitorStateException(); Node first = firstWaiter; if (first != null) doSignalAll(first); } private void doSignalAll(Node first) { lastWaiter = firstWaiter = null; do { Node next = first.nextWaiter; first.nextWaiter = null; transferForSignal(first); first = next; } while (first != null); } final boolean transferForSignal(Node node) { if (!compareAndSetWaitStatus(node, Node.CONDITION, 0)) return false; Node p = enq(node); int ws = p.waitStatus; if (ws > 0 || !compareAndSetWaitStatus(p, ws, Node.SIGNAL)) LockSupport.unpark(node.thread); return true; }
代码逻辑很清晰,从头节点开始唤醒所有节点。
下面我们在来看看awaitNanos方法,该方法可以让线程在指定的时间后被唤醒,或是被signal唤醒。
public final long awaitNanos(long nanosTimeout) throws InterruptedException { if (Thread.interrupted()) throw new InterruptedException(); Node node = addConditionWaiter(); int savedState = fullyRelease(node); final long deadline = System.nanoTime() + nanosTimeout; int interruptMode = 0; while (!isOnSyncQueue(node)) { if (nanosTimeout <= 0L) { transferAfterCancelledWait(node); break; } if (nanosTimeout >= spinForTimeoutThreshold) LockSupport.parkNanos(this, nanosTimeout); if ((interruptMode = checkInterruptWhileWaiting(node)) != 0) break; nanosTimeout = deadline - System.nanoTime(); } if (acquireQueued(node, savedState) && interruptMode != THROW_IE) interruptMode = REINTERRUPT; if (node.nextWaiter != null) unlinkCancelledWaiters(); if (interruptMode != 0) reportInterruptAfterWait(interruptMode); return deadline - System.nanoTime(); }
重点看一下这段
while (!isOnSyncQueue(node)) { if (nanosTimeout <= 0L) { transferAfterCancelledWait(node); break; } if (nanosTimeout >= spinForTimeoutThreshold) LockSupport.parkNanos(this, nanosTimeout); if ((interruptMode = checkInterruptWhileWaiting(node)) != 0) break; nanosTimeout = deadline - System.nanoTime(); }
当nanosTimeout小于0即等待时间已到或已超过时,执行transferAfterCancelledWait方法:
final boolean transferAfterCancelledWait(Node node) { if (compareAndSetWaitStatus(node, Node.CONDITION, 0)) { enq(node); return true; } while (!isOnSyncQueue(node)) Thread.yield(); return false; }
尝试更新节点状态,若更新失败的话直到节点从队列移除后返回。
在往下,spinForTimeoutThreshold值为1000,在这里的话就是1毫秒,因此在这里我们可以看到:当等待时间超过1毫秒时将线程挂起,但是挂起的这段时间可能被其他线程唤醒,因此在不足1毫秒时用忙等的方式等待等待时间的结束。最后方法返回实际的等待时间,
- Condition实现原理
- java并发等待条件的实现原理(Condition)
- AbstractQueuedSynchronizer 中的condition原理
- Condition的实现分析
- Java Thread&Concurrency(14): 深入理解条件队列(Condition)及其实现原理
- java并发锁ReentrantLock源码分析二之Condition实现原理
- 深入剖析基于并发AQS的(独占锁)重入锁(ReetrantLock)及其Condition实现原理
- 深入剖析基于并发AQS的(独占锁)重入锁(ReetrantLock)及其Condition实现原理
- 关于实现条件condition-get
- Condition实现阻塞序列1
- Lock中Condition的实现
- ReentrantLock的实现,加上Condition
- Java多线程Condition接口原理详解
- Condition
- Condition
- Condition
- Condition
- Condition
- hello world 编译出错
- python(四) 求两数的GCD(最大公约数)
- HDU:1551 Cable master(二分)
- sdut oj3330 顺序表应用6:有序顺序表查询
- 配置Eclipse来调试并发代码
- Condition实现原理
- struts的几个小异常
- 线程的调度
- MATLAB - plot函数
- HDU_1907&2509 博弈(Nim博弈变形)
- (18)HTML标签详解之<div> <span>
- sdut oj3329 顺序表应用5:有序顺序表归并
- Xamarin For Visual Studio第二坑 - 虚拟机调试
- 关闭chrome访问麦克风标签页上小红点的方法