ArrayBlockingQueue和LinkedBlockingQueue队列
          在集合框架里,想必都用过ArrayList和LinkedList,ArrayList和ArrayBlockingQueue一样,内部基于数组来存放元素,而LinkedBlockingQueue则和LinkedList一样,内部基于链表来存放元素。
队列常见的出队和入队方法

根据下面代码看下 [ArrayBlockingQueue] 的源码
ArrayBlockingQueue<String> queue = new ArrayBlockingQueue<>(20,true);
        queue.put("element");//阻塞方法
        String element = queue.take();//阻塞方法
[ArrayBlockingQueue] 构造方法
    public ArrayBlockingQueue(int capacity, boolean fair) {
        if (capacity <= 0)
            throw new IllegalArgumentException();
        this.items = new Object[capacity];
        lock = new ReentrantLock(fair);
        notEmpty = lock.newCondition();
        notFull =  lock.newCondition();
    }
元素入队列 [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();//唤醒取队列阻塞的线程
}
元素入队列 [offer] 方法
    public boolean offer(E e, long timeout, TimeUnit unit)
        throws InterruptedException {
        checkNotNull(e);
        long nanos = unit.toNanos(timeout);
        final ReentrantLock lock = this.lock;
        lock.lockInterruptibly();
        try {
            while (count == items.length) {
                if (nanos <= 0)//只要时间没有超过给定值,一直自旋
                    return false;
               //自己释放锁后重新竞争锁
                nanos = notFull.awaitNanos(nanos);
            }
            enqueue(e);
            return true;
        } finally {
            lock.unlock();
        }
    }
取队列元素 [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;
    }
元素出队列 [poll] 方法
public E poll() {
    final AtomicInteger count = this.count;
    //poll方法和take方法不一样的地方,take是阻塞,poll直接返回null
    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;
}
删除队列元素 [remove] 方法
public boolean remove(Object o) {
    if (o == null) return false;
    fullyLock();//两个lock全部上锁
    try {
        for (Node<E> trail = head, p = trail.next;
             p != null;
             trail = p, p = p.next) {
            if (o.equals(p.item)) {//循环查找
                unlink(p, trail);
                return true;
            }
        }
        return false;
    } finally {
        fullyUnlock();//释放锁
    }
}
void unlink(Node<E> p, Node<E> trail) {
       //删除节点后,node之间重新指向
        p.item = null;
        trail.next = p.next;
        if (last == p)
            last = trail;
        if (count.getAndDecrement() == capacity)
            notFull.signal();
}
总结两者的区别:
1.ArrayBlockingQueue是有界的,而LinkedBlockingQueue默认是无界的(可以通过指定大小来变为有界)。ArrayBlockingQueue有界就意味着我们使用ArrayBlockingQueue必须指定capacity大小。这样的话,内存空间会直接预先分配好,所以在使用LinkedBlockingQueue无界情况下时要考虑到内存实际使用问题,防止内存溢出问题的发生。
2.锁使用的比较。ArrayBlockingQueue内部使用1个锁来控制队列项的插入、取出操作,而LinkedBlockingQueue则是使用了2个锁来控制,一个名为putLock,另一个是takeLock,但是锁的本质都是ReentrantLock。因为LinkedBlockingQueue使用了2个锁的情况下,所以在一定程度上提升了LinkedBlockingQueue支持高并发的场景操作。
3.在ArrayBlockingQueue内部,因为是直接使用数组空间的,而且都是预先分配好的,所以操作没有那么复杂,而在LinkedBlockingQueue中,是通过链表进行维护的,而且每次插入的对象还要转为Node<>(e)对象,相当于多做了一步操作,但是根据LinkedBlockingQueue的官方描述,它是具有更好吞吐性能的。
官方解释:
               
=========================================================================================================================================
我只是一粒简单的石子,未曾想掀起惊涛骇浪,也不愿随波逐流
每个人都很渺小,努力做自己,不虚度光阴,做真实的自己,无论是否到达目标点,既然选择了出发,便勇往直前
我不能保证所有的东西都是对的,但都是能力范围内的深思熟虑和反复斟酌
 
                    
                     
                    
                 
                    
                
 
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号