展开
拓展 关闭
订阅号推广码
GitHub
视频
公告栏 关闭

LinkedBlockingQueue使用及源码分析

  • 简介
在并发编程中,LinkedBlockingQueue使用的非常频繁。因其可以作为生产者消费者的中间商 
    add()  实际上调用的是offer,区别是在队列满的时候,add会报异常 
    offer()  对列如果满了,直接入队失败 
    put("111")  在队列满的时候,会进入阻塞的状态 
    remove()  直接调用poll,唯一的区别即使remove会抛出异常,而poll在队列为空的时候直接返回null 
    poll()  在队列为空的时候直接返回null 
    take()  在队列为空的时候,会进入等待的状态
  • 案例1
public class Demo2 {
    public static void main(String[] args) throws InterruptedException {
        LinkedBlockingQueue<String> strings = new LinkedBlockingQueue<>();
        //往队列里存元素
        strings.add("111");
        strings.offer("111");
        strings.put("111");
        //从队列中取元素
        String remove = strings.remove();
        strings.poll();
        strings.take();
    }
}
  • add方法源码
# 查看add方法
    public boolean add(E e) {
        if (offer(e))
            return true;
        else
            throw new IllegalStateException("Queue full");
    }

# 查看offer方法
boolean offer(E e);

    public boolean offer(E e) {
        if (e == null) throw new NullPointerException();  // 判断是否为null,为null则抛出异常
        final AtomicInteger count = this.count;    // 获取当前队列的元素个数
        if (count.get() == capacity)    // 是否是最大容量
            return false;
        final int c;
        final Node<E> node = new Node<E>(e);    // new 1个Node
        final ReentrantLock putLock = this.putLock;    // 获取到锁,并打开锁
        putLock.lock();
        try {
            if (count.get() == capacity)    // 如果当前队列的个数小于容量
                return false;
            enqueue(node);      // 则执行入队
            c = count.getAndIncrement();    // 自增后
            if (c + 1 < capacity)      // 队列还没满时
                notFull.signal();    //  随机唤醒1个线程
        } finally {
            putLock.unlock();
        }
        if (c == 0)
            signalNotEmpty();
        return true;
    }

# 查看Node
    static class Node<E> {
        E item;    // 当前元素

        /**
         * One of:
         * - the real successor Node
         * - this Node, meaning the successor is head.next
         * - null, meaning there is no successor (this is the last node)
         */
        Node<E> next;    // 下一个元素

        Node(E x) { item = x; }
    }

# 查看如对方法,把元素添加到队列末尾
    private void enqueue(Node<E> node) {
        // assert putLock.isHeldByCurrentThread();
        // assert last.next == null;
        last = last.next = node;
    }
  • 查看put方法源码
    public void put(E e) throws InterruptedException {
        if (e == null) throw new NullPointerException();    // 判断是否为null
        final int c;
        final Node<E> node = new Node<E>(e);    // 获取Node
        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) {    // 如果队列中元素等于最大容量
                notFull.await();    // 队列挂起
            }
            enqueue(node);      // 入队
            c = count.getAndIncrement();    // 自增
            if (c + 1 < capacity)      // 队列数量小于最大容量,随机唤醒1个线程
                notFull.signal();
        } finally {
            putLock.unlock();
        }
        if (c == 0)
            signalNotEmpty();      // 唤醒所有等待线程
    }
  • 查看remove方法
    public E remove() {
        E x = poll();
        if (x != null)
            return x;
        else
            throw new NoSuchElementException();
    }

# 查看poll实现
    E poll();

    public E poll() {
        final AtomicInteger count = this.count;      // 获取队列中元素个数
        if (count.get() == 0)
            return null;
        final E x;
        final int c;
        final ReentrantLock takeLock = this.takeLock;      // 获取锁
        takeLock.lock();
        try {
            if (count.get() == 0)      // 若队列中有数据
                return null;
            x = dequeue();          // 执行dequeue方法
            c = count.getAndDecrement();      // 自减
            if (c > 1)
                notEmpty.signal();
        } finally {
            takeLock.unlock();    // 释放锁
        }
        if (c == capacity)
            signalNotFull();      // 唤醒所有等待线程
        return x;
    }

# 查看dequeue方法:将头节点移除,将下一个节点作为头节点
    private E dequeue() {
        // assert takeLock.isHeldByCurrentThread();
        // assert head.item == null;
        Node<E> h = head;
        Node<E> first = h.next;
        h.next = h; // help GC
        head = first;
        E x = first.item;
        first.item = null;
        return x;
    }
  • 查看take源码
    public E take() throws InterruptedException {
        final E x;
        final int c;
        final AtomicInteger count = this.count;      // 获取队列中元素个数
        final ReentrantLock takeLock = this.takeLock;    // 获取锁
        takeLock.lockInterruptibly();
        try {
            while (count.get() == 0) {      // 队列中元素个数为0
                notEmpty.await();        // 阻塞队列,阻止线程去队列中取元素
            }
            x = dequeue();      // 否则出队列
            c = count.getAndDecrement();      // 自减
            if (c > 1)
                notEmpty.signal();
        } finally {
            takeLock.unlock();
        }
        if (c == capacity)
            signalNotFull();
        return x;
    }
posted @ 2022-05-15 22:42  DogLeftover  阅读(41)  评论(0编辑  收藏  举报