Board logo

标题: Java 容器源码分析之ArrayBlockingQueue和LinkedBlockingQueue(4) [打印本页]

作者: look_w    时间: 2019-1-11 18:35     标题: 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个锁同时加锁。




欢迎光临 电子技术论坛_中国专业的电子工程师学习交流社区-中电网技术论坛 (http://bbs.eccn.com/) Powered by Discuz! 7.0.0