最近工作中看见一个同事的代码是关于ArrayBlockingQueue方面的使用,然后引出take()和poll()的小小的区别,当然他实现方式是没有错.但是由于选择不当有性能的开销,所以我想这里整理一下关于ArrayBlockingQueue 的理解,纯技术交流.有不正确的地方请谅解.下面对源码做一个导读.首先 ArrayBlockingQueue是一个基于数组、先进先出、线程安全的集合类,其特点是实现指定时间的阻塞读写,并且容量有界的。 1) 构造函数 public ArrayBlockingQueue(int capacity, boolean fair) { if (capacity <= 0) throw new IllegalArgumentException(); this.items = (E[]) new Object[capacity]; lock = new ReentrantLock(fair); notEmpty = lock.newCondition(); notFull = lock.newCondition(); } 初始化锁和两个锁上的Condition,一个为notEmpty,一个为notFull。 2. offer添加 public boolean offer(E e, long timeout, TimeUnit unit) throws InterruptedException { if (e == null) throw new NullPointerException(); long nanos = unit.toNanos(timeout); final ReentrantLock lock = this.lock; lock.lockInterruptibly(); try { for (;;) { if (count != items.length) { insert(e); return true; } if (nanos <= 0) return false; try { nanos = notFull.awaitNanos(nanos); } catch (InterruptedException ie) { notFull.signal(); // propagate to non-interrupted thread throw ie; } } } finally { lock.unlock();---一定要释放 } } 这个方法将元素插入数组的末尾,如果数组满,则进入等待,只到以下三种情况发生才继续:被唤醒、达到指定的时间、当前线程被中断。该方法首先将等待时间转换成纳秒。然后加锁,如果数组未满,则在末尾插入数据,如果数组已满,则调用notFull.awaitNanos进行等待。如果被唤醒或超时,重新判断是否满。如果线程被interrupt,则直接抛出异常。同时还可以选择put方法,此方法在数组已满的情况下会一直等待,知道数组不为空或线程被interrupt. public void put(E e) throws InterruptedException { if (e == null) throw new NullPointerException(); final E[] items = this.items; final ReentrantLock lock = this.lock; lock.lockInterruptibly(); try { try { while (count == items.length)--本质是使用wait/notify机制就可以避免这些无谓的轮询,节省CPU的消耗 notFull.await(); } catch (InterruptedException ie) { notFull.signal(); // propagate to non-interrupted thread throw ie; } insert(e); } finally { lock.unlock(); } } 接下来介绍重点的一对方法 public E poll() { final ReentrantLock lock = this.lock; lock.lock(); try { return (count == 0) ? null : extract();----空直接返回null,那么我们如何判定集合中的数据状况呢?我们就采用重入锁内部通过Sync轮询机制。这样是非常耗费CPU的. } finally { lock.unlock(); } } } } finally { lock.unlock(); } } public E take() throws InterruptedException { final ReentrantLock lock = this.lock; lock.lockInterruptibly(); try { while (count == 0) notEmpty.await();---为空阻塞.本质是使用wait/notify机制就可以避免这些无谓的轮询,节省CPU的消耗 return extract(); } finally { lock.unlock(); } } ArrayBlockingQueue take()和poll()的一点区别 使用take()函数,如果队列中没有数据,则线程wait释放CPU,而poll()则不会等待,直接返回null;同样,空间耗尽时offer()函数不会等待,直接返回false,而put()则会wait,因此如果你使用while(true)来获得队列元素,千万别用poll(),CPU会100%的. |
行业聚焦 面试交流 职位推荐 开发视频 技术交流 腾讯微博 新浪微博
友情链接:课课家教育 阿里云 鲜果 W3Cfuns前端网 中国企业家 环球企业家 投资界 传媒梦工场 MSN中文网 Android开发者社区 cnbeta 投资中国网 又拍云存储 美通说传播 IT茶馆 网商在线 商业评论网 TechOrange IT时代周刊 3W创新传媒 开源中国社区 二维工坊 Iconfans 推酷 智能电视网 FreeBuf黑客与极客 财经网 DoNews 凤凰财经 新财富 eoe移动开发者社区 i黑马 网易科技 新浪科技 搜狐IT 创业家 创业邦 腾讯财经 福布斯中文网 天下网商 TechWeb 雷锋网 新浪创业 和讯科技 品途O2O 极客公园 艾瑞网 抽屉新热榜 卖家网 人民网通信频道 拉勾网 创新派 简单云主机
手机版|黑名单|守望者 成才网 在线教育 linux 高级程序设计 C/C++ 大数据
( 蜀ICP备14029946号 )
成都守望者科技有限公司 © 2013-2016 All Rights Reserved