阻塞队列之LinkedBlockingQueue

大家推荐个靠谱的公众号程序员探索之路,公众号内点击网赚获取彩蛋,大家一起加油,这个公众号已经接入图灵https://i-blog.csdnimg.cn/blog_migrate/93320939ba8f8b0a898e29429753f496.png ​ 

这里面有其他文章的知识如有不懂请看其他文章

===============
1.LinkedBlockingQueue的属性
===============    
    /** The capacity bound, or Integer.MAX_VALUE if none 
    队列的容量
    */
    private final int capacity;

    /** Current number of elements 
    队列中的元素数量
    */
    private final AtomicInteger count = new AtomicInteger();

    /**
     * Head of linked list.
     * Invariant: head.item == null
     队列头元素
     */
    transient Node<E> head;

    /**
     * Tail of linked list.
     * Invariant: last.next == null
     队列尾部元素
     */
    private transient Node<E> last;

    /** Lock held by take, poll, etc 
    读锁
    */
    private final ReentrantLock takeLock = new ReentrantLock();

    /** Wait queue for waiting takes 
    如果队列是空是 那么会notEmpty.await方法使读线程等待
    */
    private final Condition notEmpty = takeLock.newCondition();

    /** Lock held by put, offer, etc 
    写锁
    */
    private final ReentrantLock putLock = new ReentrantLock();

    /** Wait queue for waiting puts 
    如果队列使满的话,那么会notFull.await方法使写线程等待
    */
    private final Condition notFull = putLock.newCondition();
===============
2.LinkedBlockingQueue的Node内部类
===============    
    /**
     * Linked list node class
     */
    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; }
    }
===============
3.LinkedBlockingQueue的构造器
===============    
    /**
     * Creates a {@code LinkedBlockingQueue} with a capacity of
     * {@link Integer#MAX_VALUE}.
     这个也就是传说中的无界队列   其实也就是容量为Integer.MAX_VALUE的队列
     */
    public LinkedBlockingQueue() {
        this(Integer.MAX_VALUE);
    }

    /**
     * Creates a {@code LinkedBlockingQueue} with the given (fixed) capacity.
     *
     * @param capacity the capacity of this queue
     * @throws IllegalArgumentException if {@code capacity} is not greater
     *         than zero
     指定容量的队列
     */
    public LinkedBlockingQueue(int capacity) {
        if (capacity <= 0) throw new IllegalArgumentException();
        this.capacity = capacity;
        //初始化一个空的对头和队尾
        last = head = new Node<E>(null);
    }
    /**
     * Creates a {@code LinkedBlockingQueue} with a capacity of
     * {@link Integer#MAX_VALUE}, initially containing the elements of the
     * given collection,
     * added in traversal order of the collection's iterator.
     *
     * @param c the collection of elements to initially contain
     * @throws NullPointerException if the specified collection or any
     *         of its elements are null
     这个是你在初始化的时候可以传入一个集合  会把集合中的元素放入到队列中
     这个构造器看完后的方法就明白了
     */
    public LinkedBlockingQueue(Collection<? extends E> c) {
        this(Integer.MAX_VALUE);
        final ReentrantLock putLock = this.putLock;
        putLock.lock(); // Never contended, but necessary for visibility
        try {
            int n = 0;
            for (E e : c) {
                if (e == null)
                    throw new NullPointerException();
                if (n == capacity)
                    throw new IllegalStateException("Queue full");
                enqueue(new Node<E>(e));
                ++n;
            }
            count.set(n);
        } finally {
            putLock.unlock();
        }
    }
===============
4.put方法
===============    
    /**
     * Inserts the specified element at the tail of this queue, waiting if
     * necessary for space to become available.
     *
     * @throws InterruptedException {@inheritDoc}
     * @throws NullPointerException {@inheritDoc}
     */
    public void put(E e) throws InterruptedException {
        //e不能为null
        if (e == null) throw new NullPointerException();
        // Note: convention in all put/take/etc is to preset local var
        // holding count negative to indicate failure unless set.
        int c = -1;
        //新建node对象
        Node<E> node = new Node<E>(e);
        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);
            //注意这里 队列中的元素已经+1  但是c = 入队之前的容量
            c = count.getAndIncrement();
            //这个if什么情况下会成立呢  如果写线程有很多个写线程都在 notFull的条件队列中 此时入队之后的队列元素还是
            //小于对列容量 那么就可以再唤醒一个写线程
            if (c + 1 < capacity)
                notFull.signal();
        } finally {
            putLock.unlock();
        }
        //注意这个c是入队之前的容量  那么c == 0(注意head并不算队列中的元素
        再后面出对方法中也是返回head.next) 就是说入队之前 队列是空的  那么就可以看下 
        //是否有读线程等待,也就是做一个读线程唤醒操作
        if (c == 0)
            signalNotEmpty();
    }

    /**
     * Links node at end of queue.
     *
     * @param node the node
     入队方法 其实就是把node放到末尾   LinkedBlockingQueue的属性last = node
     */
    private void enqueue(Node<E> node) {
        // assert putLock.isHeldByCurrentThread();
        // assert last.next == null;
        last = last.next = node;
    }

    /**
     * Signals a waiting take. Called only from put/offer (which do not
     * otherwise ordinarily lock takeLock.)
     //读线程唤醒
     */
    private void signalNotEmpty() {
        final ReentrantLock takeLock = this.takeLock;
        takeLock.lock();
        try {
            notEmpty.signal();
        } finally {
            takeLock.unlock();
        }
    }
===============
5.take方法
===============    
/**
 * 这个take和put方法套路都差不多
 */
    public E take() throws InterruptedException {
        E x;
        int c = -1;
        final AtomicInteger count = this.count;
        final ReentrantLock takeLock = this.takeLock;
        takeLock.lockInterruptibly();
        try {
            //如果 队列是空的 那么读线程等待
            while (count.get() == 0) {
                notEmpty.await();
            }
            //走到这里说明队列不是空的 那么就出对
            x = dequeue();
            c = count.getAndDecrement();
            //同样的套路 如果出对前队列中的元素 大于1 那么可以再唤醒一个读线程
            if (c > 1)
                notEmpty.signal();
        } finally {
            takeLock.unlock();
        }
        //如果 在这个节点出对之前 队列是满的 可以唤醒写线程
        if (c == capacity)
            signalNotFull();
        return x;
    }


    /**
     * Removes a node from head of queue.
     *
     * @return the node
     出对方法
     可以看到 把head与队列断开关系  head = first(就是原head的next) 返回first的item
     */
    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;
    }

    /**
     * Signals a waiting put. Called only from take/poll.
     //唤醒写线程
     */
    private void signalNotFull() {
        final ReentrantLock putLock = this.putLock;
        putLock.lock();
        try {
            notFull.signal();
        } finally {
            putLock.unlock();
        }
    }

/**
 * 读取队列首元素  不出对
 * @return {[type]} [description]
 */
    public E peek() {
        if (count.get() == 0)
            return null;
        final ReentrantLock takeLock = this.takeLock;
        takeLock.lock();
        try {
            Node<E> first = head.next;
            if (first == null)
                return null;
            else
                return first.item;
        } finally {
            takeLock.unlock();
        }
    }

/**
 * 获取元素 当队列中没有元素 返回null
 * @return {[type]} [description]
 */
    public E poll() {
        final AtomicInteger count = this.count;
        if (count.get() == 0)
            return null;
        E x = null;
        int c = -1;
        final ReentrantLock takeLock = this.takeLock;
        takeLock.lock();
        try {
            if (count.get() > 0) {
                x = dequeue();
                c = count.getAndDecrement();
                if (c > 1)
                    notEmpty.signal();
            }
        } finally {
            takeLock.unlock();
        }
        if (c == capacity)
            signalNotFull();
        return x;
    }

/**
 * 写入元素  当队列满是返回false
 * @param  {[type]} E e             [description]
 * @return {[type]}   [description]
 */
    public boolean offer(E e) {
        if (e == null) throw new NullPointerException();
        final AtomicInteger count = this.count;
        if (count.get() == capacity)
            return false;
        int c = -1;
        Node<E> node = new Node<E>(e);
        final ReentrantLock putLock = this.putLock;
        putLock.lock();
        try {
            if (count.get() < capacity) {
                enqueue(node);
                c = count.getAndIncrement();
                if (c + 1 < capacity)
                    notFull.signal();
            }
        } finally {
            putLock.unlock();
        }
        if (c == 0)
            signalNotEmpty();
        return c >= 0;
    }
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值