java LinkedBlockingQueue源码简析
来源:互联网 发布:php 页面重定向方法 编辑:程序博客网 时间:2024/05/22 23:55
阻塞队列的操作,当不能立即满足时(但将来可能会满足),有4种形式处理方式:
1抛异常;2返回特殊值;3阻塞;4等待特定时间(时间内操作被满足返回true,超时返回false)
这里分析其阻塞的处理方式。
现在来看put方法的源码
public void put(E e) throws InterruptedException { if (e == null) throw new NullPointerException(); // Note: convention in all put/take/etc is to preset local var // holding count negative to indicate failure unless set. int c = -1; Node<E> node = new Node<E>(e);//创建新节点,节点中包含一个数据字段item=e,和一个指针字段next final ReentrantLock putLock = this.putLock; final AtomicInteger count = this.count; putLock.lockInterruptibly();//加锁(默认是非公平的) try { /* * Note that count is used in wait guard even though it is * not protected by lock. This works because count can * only decrease at this point (all other puts are shut * out by lock), and we (or some other waiting put) are * signalled if it ever changes from capacity. Similarly * for all other uses of count in other wait guards. */ while (count.get() == capacity) {//LinkedBlockingQueue队满时进入循环 notFull.await();//主要包括操作三个:放入等待队列,释放锁,阻塞 } enqueue(node);//入队 c = count.getAndIncrement();//返回原值 if (c + 1 < capacity) notFull.signal();//如果当前队列未满,则signal非满条件,signal操作为:将等待队列中的firstwaiter出队,并进入同步队列,检查,如果同步队列中的前一个节点已经cancelled,则unpark刚进入的这个节点(否则不对这个节点进行处理) } finally { putLock.unlock();//解锁 } if (c == 0) signalNotEmpty();//如果队列中只有一个节点,则signal非空条件,操作如notFull.signal() }
public final void await() throws InterruptedException { if (Thread.interrupted()) throw new InterruptedException(); Node node = addConditionWaiter();//将当前线程加入等待队列,并设置状态为condition int savedState = fullyRelease(node);//根据addConditionWaiter中新加节点可知,返回的state为condition。这里还会释放锁(即, 锁计数器减一,并unpark下一个节点(此处并不出队首节点,首节点在获取锁时出队),以便激活阻塞线程,并获得锁) int interruptMode = 0; while (!isOnSyncQueue(node)) {//不在同步队列(与等待队列区别)中时(此时线程已获得锁,必然在同步队列中,但此方法中还有一个判断条件是状态是否为condition,若是则返回false),进入循环 LockSupport.park(this);//阻塞在这里(并放弃锁,从而使得其他线程也可阻塞在这里,即等待队列中包含多个节点(线程)),不会向下进行,当signal发生时会继续执行;中断发生时,抛出 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); }
private Node addConditionWaiter() {//将线程加入等待队列,并设置状态为condition 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; }
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; } }
public final boolean release(int arg) { if (tryRelease(arg)) {//尝试释放锁 Node h = head; if (h != null && h.waitStatus != 0) unparkSuccessor(h);//unpark后继线程 return true; } return false; }
protected final boolean tryRelease(int releases) { int c = getState() - releases; if (Thread.currentThread() != getExclusiveOwnerThread()) throw new IllegalMonitorStateException(); boolean free = false; if (c == 0) {//如果没有线程持有锁 free = true;//释放锁成功 setExclusiveOwnerThread(null);//设置独占线程为null } setState(c); return free; }
private void unparkSuccessor(Node node) {//unpark后继线程 /* * If status is negative (i.e., possibly needing signal) try * to clear in anticipation of signalling. It is OK if this * fails or if status is changed by waiting thread. */ int ws = node.waitStatus; if (ws < 0) compareAndSetWaitStatus(node, ws, 0); /* * Thread to unpark is held in successor, which is normally * just the next node. But if cancelled or apparently null, * traverse backwards from tail to find the actual * non-cancelled successor. */ Node s = node.next; if (s == null || s.waitStatus > 0) { s = null; for (Node t = tail; t != null && t != node; t = t.prev) if (t.waitStatus <= 0) s = t; } if (s != null) LockSupport.unpark(s.thread); }
Take方法细节可从put方法推出,就不分析了。
<pre name="code" class="java">public E take() throws InterruptedException { E x; int c = -1; final AtomicInteger count = this.count; final ReentrantLock takeLock = this.takeLock; takeLock.lockInterruptibly(); try { while (count.get() == 0) {//如果队列为空进入循环 notEmpty.await();//加入等待队列(与notFull.await()不是一个等待队列),释放锁,阻塞 } x = dequeue();//出队 c = count.getAndDecrement(); if (c > 1)//队列非空 notEmpty.signal();//notFull等待队列出队一节点,节点入队同步队列 } finally { takeLock.unlock(); } if (c == capacity) signalNotFull(); return x; }
0 0
- java LinkedBlockingQueue源码简析
- java源码分析09-LinkedBlockingQueue
- java源码阅读之LinkedBlockingQueue
- Java中一个LinkedBlockingQueue源码的问题
- 《Java源码分析》:BlockingQueue之LinkedBlockingQueue
- java LinkedBlockingQueue
- Java集合源码学习(17)_BlockingQueue接口的实现LinkedBlockingQueue
- 源码解析关于java阻塞容器:ArrayBlockingQueue,LinkedBlockingQueue等
- Java 并发 --- 阻塞队列之LinkedBlockingQueue源码分析
- LinkedBlockingQueue源码解析
- LinkedBlockingQueue 源码学习
- LinkedBlockingQueue源码分析
- LinkedBlockingQueue源码阅读
- 源码分析-LinkedBlockingQueue
- LinkedBlockingQueue源码分析
- LinkedBlockingQueue源码解析
- LinkedBlockingQueue源码分析
- LinkedBlockingQueue源码分析
- freemarker遍历集合
- 2015 去哪儿校招---字符串中第一个重复的字符
- IOS上关于状态栏的相关设置(UIStatusBar)
- 进入it世界的一年多
- 对象构造器和原型
- java LinkedBlockingQueue源码简析
- android framework 图解
- CentOS7防火墙
- Docker教程
- 快速定位是否是kl文件问题
- android 自定义属性的使用一、在res/values文件下定义一个attrs.xml文件,代码如下
- postgreSql 中自定义的字段和数据库关键字重名
- 2015 去哪儿校招---二分查找
- 计算机系统中的编码问题