BlockingQueue源码

636 阅读2分钟

概述

  • BlockingQueue是阻塞队列。
  • BlockingQueue继承自Queue,在Queue的基础上添加了阻塞方法put()和take(),
  • BlockingQueue是接口,由实现类实现相应的阻塞方法。例如:ArrayBlockingQueue,SychronousQueue,TranferQueue,LinkedBlockingQueue,PriorityBlockingQueue等等。

ArrayBlockingQueue

底层是通过数组作为容器存储,使用的是reentrantLock进行加锁,使用不同的condition进行不同操作

//数组用于存储数据
final Object[] items;
 /** 用于put操作的condition  */
    private final Condition notFull;
     /** 用于take操作的condition */
    private final Condition notEmpty;   
    
 public void put(E e) throws InterruptedException {
       //判断非空
       checkNotNull(e);
        final ReentrantLock lock = this.lock;
        //加锁可被打断
        lock.lockInterruptibly();
        try {
            //当数据到达上限时,将put的condition等待 
            while (count == items.length)
                notFull.await();
            enqueue(e);//添加到数组容器中
        } finally {
            lock.unlock();//释放锁
        }
    }

  public E take() throws InterruptedException {
        final ReentrantLock lock = this.lock;
        lock.lockInterruptibly();//可打断锁
        try {
            while (count == 0) //如果数据为空,就让take的condition等待
                notEmpty.await();
            return dequeue(); 
        } finally {
            lock.unlock();
        }
    }

LinkedBlockingQueue

底层是用链表存储,take获取的是head.next ,put插入的是末尾,可以进行读写分离

   读写锁分离
    private final ReentrantLock takeLock = new ReentrantLock();

    private final Condition notEmpty = takeLock.newCondition();

    private final ReentrantLock putLock = new ReentrantLock();

    private final Condition notFull = putLock.newCondition();

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.lockInterruptibly();
        try {
            //如果到达上限就让put的condition 等待  
            while (count.get() == capacity) {
                notFull.await();
            }
            enqueue(node);//添加数据
            c = count.getAndIncrement();
            if (c + 1 < capacity) //如果数据添加后没有到达上限,唤醒notFull
                notFull.signal();
        } finally {
            putLock.unlock();
        }
        if (c == 0) //当有一条数据插入是,就可以将notEmpty唤醒了
            signalNotEmpty();
    }
    
    
    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) {//数据为空时,takecondition等待
                notEmpty.await();
            }
            x = dequeue();
            c = count.getAndDecrement();
            if (c > 1)
                notEmpty.signal();
        } finally {
            takeLock.unlock();
        }
        if (c == capacity)
            signalNotFull();
        return x;
    } 

PriorityBlockingQueue

优先级缓存队列,默认是小根堆,可以添加比较器来自定义

//三种构造方式 ,无参,设置默认长度,比价器
 public PriorityBlockingQueue() {
        this(DEFAULT_INITIAL_CAPACITY, null);
    }
    
 public PriorityBlockingQueue(int initialCapacity) {
        this(initialCapacity, null);
    }
    
 public PriorityBlockingQueue(int initialCapacity,
                                 Comparator<? super E> comparator) {
        if (initialCapacity < 1)
            throw new IllegalArgumentException();
        this.lock = new ReentrantLock();
        this.notEmpty = lock.newCondition();
        this.comparator = comparator;
        this.queue = new Object[initialCapacity];
    }


PUT方法 因为是数组存储,先判断是否需要扩容,默认每次扩大为原来的1.5倍, 如果没设置比较器就用默认的(小根堆),有设置就用自定义的比较器

 public void put(E e) {
        offer(e); 
    }
    
    public boolean offer(E e) {
        if (e == null)
            throw new NullPointerException();
        final ReentrantLock lock = this.lock;
        lock.lock();
        int n, cap;
        Object[] array;
        while ((n = size) >= (cap = (array = queue).length))
            tryGrow(array, cap);//扩容
        try {
            Comparator<? super E> cmp = comparator;
            if (cmp == null)
                siftUpComparable(n, e, array); //使用默认比较器
            else
                siftUpUsingComparator(n, e, array, cmp); //自定义比较器
            size = n + 1;
            notEmpty.signal();
        } finally {
            lock.unlock();
        }
        return true;
    }

take方法

public E take() throws InterruptedException {
        final ReentrantLock lock = this.lock;
        lock.lockInterruptibly();
        E result;
        try {
            while ( (result = dequeue()) == null)
                notEmpty.await();
        } finally {
            lock.unlock();
        }
        return result;
    }

  /**
     * 怎么存,怎么取,使用相同的比较器去移除数据
     */
    private E dequeue() {
        int n = size - 1;
        if (n < 0)
            return null;
        else {
            Object[] array = queue;
            E result = (E) array[0];
            E x = (E) array[n];
            array[n] = null;
            Comparator<? super E> cmp = comparator;
            if (cmp == null)
                siftDownComparable(0, x, array, n);
            else
                siftDownUsingComparator(0, x, array, n, cmp);
            size = n;
            return result;
        }
    }