学习BlockingQueue之PriorityBlockingQueue实现原理

 

一:概念

  PriorityBlockingQueue 是一个支持优先级的无界阻塞队列。默认情况下元素 采取自然顺序升序排列。也可以自定义类实现 compareTo()方法来指定元素排序 规则,

或者初始化 PriorityBlockingQueue 时,指定构造参数 Comparator 来对元素 进行排序。需要注意的是不能保证同优先级元素的顺序。

 

二:示例

main方法测试方法:

 

 

生产者线程:

 

 

消费者线程:

 

 

 

通过输出结果可以看出数据在对列里面已经排序,所以消费者线程消费的时候是有序的。

 

三:看一下PriorityBlockingQueue 这个类的源码

默认容量 11

 

数组最大分配值

 

 

 内部维护一个数组

 

 

比较器,可以不初始化,但是对象必须具有比较性

 

 只有一把锁,锁所有的public操作

 

 

 

看一下构造方法:

入参有初始容量、比较器

 

 还可以初始化一个容器

 

 

 

看一下offer和poll方法:

offer方法:

如果入参元素为null,则抛异常,  加锁,如果元素的数量等于数组的容量时,就要扩容;如果数组还有空间时,就会入队,

入队会判断是否初始化比较器,如果有比较器,则按照比较器就行排序,没有,则元素必须具有可比较性

 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;
    }

  

看一下扩容方法tryGrow

 

 

 

 

poll方法:

上锁,然后调用出队方法:

 public E poll() {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            return dequeue();
        } finally {
            lock.unlock();
        }
    }

  

如果对列为空,则返回null,如果不为空,则把第一个元素返回,然后重新排序

 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;
        }
    }

  

 

add和remove方法:

add方法的实现就是使用offer的逻辑

 

 

remove方法:

1:加锁  2:根据对象找到在数组中的索引 3:根据索引删除元素

public boolean remove(Object o) {
        final ReentrantLock lock = this.lock;
        lock.lock();
        try {
            int i = indexOf(o);
            if (i == -1)
                return false;
            removeAt(i);
            return true;
        } finally {
            lock.unlock();
        }
    }

  

根据对象寻找在数组中的下标位置

 

 

 

posted @ 2020-03-19 11:18  warrior1234  阅读(730)  评论(0编辑  收藏  举报