首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

Java 容器源码分析之ArrayBlockingQueue和LinkedBlockingQueue(4)

Java 容器源码分析之ArrayBlockingQueue和LinkedBlockingQueue(4)

数据的删除LinkedBlockingQueue有不同的几个数据删除方法,poll、take、remove方法。
poll方法:
[url=][/url]
public E poll() {    final AtomicInteger count = this.count;    if (count.get() == 0) // 如果元素个数为0        return null; // 返回null    E x = null;    int c = -1;    final ReentrantLock takeLock = this.takeLock;    takeLock.lock(); // 拿锁加锁,保证调用poll方法的时候只有1个线程    try {        if (count.get() > 0) { // 判断队列里是否还有数据            x = dequeue(); // 删除头结点            c = count.getAndDecrement(); // 元素个数-1            if (c > 1) // 如果队列里还有元素                notEmpty.signal(); // 在拿锁的条件对象notEmpty上唤醒正在等待的线程,表示队列里还有数据,可以再次消费        }    } finally {        takeLock.unlock(); // 释放拿锁,让其他线程可以调用poll方法    }    if (c == capacity) // 由于存在放锁和拿锁,这里可能放锁一直在添加数据,count会变化。这里的if条件表示如果队列中还可以再插入数据        signalNotFull(); // 在放锁的条件对象notFull上唤醒正在等待的1个线程,表示队列里还能再次添加数据                return x;}[url=][/url]

take方法:[url=][/url]
public E take() throws InterruptedException {    E x;    int c = -1;    final AtomicInteger count = this.count;    final ReentrantLock takeLock = this.takeLock;    takeLock.lockInterruptibly(); // 拿锁加锁,保证调用take方法的时候只有1个线程    try {        while (count.get() == 0) { // 如果队列里已经没有元素了            notEmpty.await(); // 阻塞并挂起当前线程        }        x = dequeue(); // 删除头结点        c = count.getAndDecrement(); // 元素个数-1        if (c > 1) // 如果队列里还有元素            notEmpty.signal(); // 在拿锁的条件对象notEmpty上唤醒正在等待的线程,表示队列里还有数据,可以再次消费    } finally {        takeLock.unlock(); // 释放拿锁,让其他线程可以调用take方法    }    if (c == capacity) // 由于存在放锁和拿锁,这里可能放锁一直在添加数据,count会变化。这里的if条件表示如果队列中还可以再插入数据        signalNotFull(); // 在放锁的条件对象notFull上唤醒正在等待的1个线程,表示队列里还能再次添加数据    return x;}[url=][/url]


remove方法:
[url=][/url]
public boolean remove(Object o) {    if (o == null) return false;    fullyLock(); // remove操作要移动的位置不固定,2个锁都需要加锁    try {        for (Node<E> trail = head, p = trail.next; // 从链表头结点开始遍历             p != null;             trail = p, p = p.next) {            if (o.equals(p.item)) { // 判断是否找到对象                unlink(p, trail); // 修改节点的链接信息,同时调用notFull的signal方法                return true;            }        }        return false;    } finally {        fullyUnlock(); // 2个锁解锁    }}[url=][/url]

LinkedBlockingQueue的take方法对于没数据的情况下会阻塞,poll方法删除链表头结点,remove方法删除指定的对象。
需要注意的是remove方法由于要删除的数据的位置不确定,需要2个锁同时加锁。
返回列表