加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 编程开发 > Java > 正文

ArrayBlockingQueue和LinkedBlockingQueue

发布时间:2020-12-15 05:32:08 所属栏目:Java 来源:网络整理
导读:? ? ? ? ? 在集合框架里,想必都用过ArrayList和LinkedList,ArrayList和 ArrayBlockingQueue 一样,内部基于数组来存放元素,而 LinkedBlockingQueue 则和LinkedList一样,内部基于链表来存放元素。 ? ? ? ? ? 队列常见的出队和入队方法 根据下面代码看下Ar

? ? ? ? ? 在集合框架里,想必都用过ArrayList和LinkedList,ArrayList和ArrayBlockingQueue一样,内部基于数组来存放元素,而LinkedBlockingQueue则和LinkedList一样,内部基于链表来存放元素。

? ? ? ? ? 队列常见的出队和入队方法


根据下面代码看下ArrayBlockingQueue的源码
ArrayBlockingQueue<String> queue = new ArrayBlockingQueue<>(20); queue.put("element");//阻塞方法
        String element = queue.take();//阻塞方法

? ?put 方法

public void put(E e) throws InterruptedException { checkNotNull(e); final ReentrantLock lock = this.lock; lock.lockInterruptibly();//获取锁,如果interrupt,直接抛出异常
    try { while (count == items.length) notFull.await();//队列满了,阻塞等待被唤醒
        enqueue(e);//入队
    } finally { lock.unlock();//释放锁
 } } private void enqueue(E x) { final Object[] items = this.items; items[putIndex] = x; if (++putIndex == items.length)//如果入队下标已满,重置putIndex
            putIndex = 0; count++;//队列总数+1
        notEmpty.signal();//唤醒取队列阻塞的线程
}

? ?take 方法

public E take() throws InterruptedException { final ReentrantLock lock = this.lock; lock.lockInterruptibly();//获取锁,如果interrupt,直接抛出异常
    try { while (count == 0) notEmpty.await();//队列空了,阻塞等待被唤醒
        return dequeue();//出队
    } finally { lock.unlock();//释放锁
 } } private E dequeue() { final Object[] items = this.items; @SuppressWarnings("unchecked") E x = (E) items[takeIndex]; items[takeIndex] = null; if (++takeIndex == items.length)//如果出队下标已满,重置takeIndex
            takeIndex = 0; count--;//总数减1 //迭代器有关
        if (itrs != null) itrs.elementDequeued(); notFull.signal();//唤醒入队列阻塞的线程
        return x; }

? ? ? ?取队列的非阻塞方法poll? 方法

    public E poll() { final ReentrantLock lock = this.lock; lock.lock(); try { return (count == 0) ? null : dequeue(); } finally { lock.unlock(); } }

? ? ? ? 其他方法类似。

?

 根据下面代码看下LinkedBlockingQueue的源码
    //如果没有指定大小,默认为Integer.MAX_VALUE,也就是无界队列
    LinkedBlockingQueue<String> queue = new LinkedBlockingQueue<>(4);
    queue.put("element");//阻塞方法
    queue.take();//阻塞方法

? ?入队 put 方法

public void put(E e) throws InterruptedException { if (e == null) throw new NullPointerException(); int c = -1; Node<E> node = new Node<E>(e); final ReentrantLock putLock = this.putLock; final AtomicInteger count = this.count; //获取putLock锁,如果interrupt,直接抛出异常
 putLock.lockInterruptibly(); try { while (count.get() == capacity) { notFull.await();//队列满了,阻塞等待被唤醒
 } enqueue(node);//入队
        c = count.getAndIncrement(); // 再次判断队列是否有可用空间,如果有唤醒下一个线程进行添加操作
        if (c + 1 < capacity) notFull.signal(); } finally { putLock.unlock();//释放putLock锁
 } if (c == 0)//唤醒取队列阻塞的线程
 signalNotEmpty(); } private void enqueue(Node<E> node) { //新增节点变为最后一个节点
        last = last.next = node; }

? ?出队 take 方法

public E take() throws InterruptedException { E x; int c = -1; final AtomicInteger count = this.count;//总数 final ReentrantLock takeLock = this.takeLock; takeLock.lockInterruptibly(); //获取takeLock锁,如果interrupt,直接抛出异常
    try { while (count.get() == 0) { notEmpty.await();//队列空了,阻塞等待被唤醒
 } x = dequeue();//出队
        c = count.getAndDecrement(); //c > 1说明c至少为2, 队列中还有元素,唤醒下一个消费线程进行消费
        if (c > 1) notEmpty.signal(); } finally { takeLock.unlock();//释放takeLock锁
 } if (c == capacity)//唤醒入队列阻塞的线程
 signalNotFull(); return x; } private E dequeue() { // 获取到head节点
        Node<E> h = head; // 获取到head节点指向的下一个节点
        Node<E> first = h.next; // head节点原来指向的节点的next指向自己,等待下次gc回收
        h.next = h; // help GC // head节点指向新的节点
        head = first; // 获取到新的head节点的item值,即队列中的元素
        E x = first.item; first.item = null; return x; }

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读