【JAVA多线程】PriorityBlockingQueue源码分析

请添加图片描述

PriorityBlockingQueue

是一个无界队列,它没有限制,在内存允许的情况下可以无限添加元素;它又是具有优先级的队列,是通过构造函数传入的对象来判断,传入的对象必须实现comparable接口。

用法

import java.util.concurrent.*;

public class Test {
    
    

    public static void main(String[] args) {
    
    

        PriorityBlockingQueue<Person> pbq = new PriorityBlockingQueue<>();
        pbq.add(new Person(3,"person3"));
        System.out.println( pbq);//[3:person3]
        pbq.add(new Person(2,"person2"));
        System.out.println( pbq);//[2:person2, 3:person3]
        pbq.add(new Person(1,"person1"));
        System.out.println( pbq);//[1:person1, 3:person3, 2:person2]
        System.out.println("获取元素 " + pbq.take().getId());
        System.out.println("容器为:" + pbq);//[2:person2, 3:person3]
        System.out.println("获取元素 " + pbq.take().getId());
        System.out.println("容器为:" + pbq);//[3:person3]
        System.out.println("获取元素 " + pbq.take().getId());
        System.out.println("容器为:" + pbq);//[]

    }


}



class Person implements Comparable<Person>{
    
    
    private int id;
    private String name;
    public int getId() {
    
    
        return id;
    }
    public void setId(int id) {
    
    
        this.id = id;
    }
    public String getName() {
    
    
        return name;
    }
    public void setName(String name) {
    
    
        this.name = name;
    }
    public Person(int id, String name) {
    
    
        this.id = id;
        this.name = name;
    }
    public Person() {
    
    
    }
    @Override
    public String toString() {
    
    
        return this.id + ":" + this.name;
    }
    @Override
    public int compareTo(Person person) {
    
    
        return this.id > person.getId() ? 1 : ( this.id < person.getId() ? -1 :0);
    }
}

对结果分析,每次添加一个元素,PriorityBlockingQueue中的person都会执行compareTo方法进行排序,但是只是把第一个元素排在首位,其他元素并没有按照顺序排序。这就保障了每次获取到的元素都是经过排序的第一个元素。

每次获取的元素都是排序后第一个元素。

成员属性

//存放数据的数组
private transient Object[] queue;
//元素个数
private transient int size;
//排序规则
private transient Comparator<? super E> comparator;
//独占锁
private final ReentrantLock lock;
//队列为空的时候的阻塞队列
private final Condition notEmpty;

入队

 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);//如果cmp==null,按照key的compare()方法来排列
            else
                siftUpUsingComparator(n, e, array, cmp);//按照cmp排列
            size = n + 1;
            notEmpty.signal();//唤醒出队等待线程
        } finally {
    
    
            lock.unlock();
        }
        return true;
    }
    
 private static <T> void siftUpUsingComparator(int k, T x, Object[] array,
                                       Comparator<? super T> cmp) {
    
    
        while (k > 0) {
    
    
            int parent = (k - 1) >>> 1;//获取parent下标,parent是从0开始编号
            Object e = array[parent];
            if (cmp.compare(x, (T) e) >= 0)//如果compare()>=0,说明就满足排序规则了
                break;
            array[k] = e;
            k = parent;//将parent的位置与child调换位置
        }
        array[k] = x;
    }

比较采用往上堆化的过程。向上堆化过程也十分简单,就是如果child节点与parent节点不符合排序规则,就将child和parent换一下位置。

出队

public E take() throws InterruptedException {
    
    
        final ReentrantLock lock = this.lock;
        lock.lockInterruptibly();//可中断式申请锁
        E result;
        try {
    
    
            while ( (result = dequeue()) == null)
                notEmpty.await(); //如果队列为空,就阻塞在notEmpty队列上
        } finally {
    
    
            lock.unlock();
        }
        return result;
    }
private E dequeue() {
    
    
        int n = size - 1;
        if (n < 0)
            return null; //如果队列为空,返回null
        else {
    
    
            Object[] array = queue;
            E result = (E) array[0];//第0个元素就是栈顶元素
            E x = (E) array[n]; //将第n个元素设置为栈顶元素,然后利用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;
        }
    }
 private static <T> void siftDownUsingComparator(int k, T x, Object[] array,
                                                    int n,
                                                    Comparator<? super T> cmp) {
    
    
        if (n > 0) {
    
    
            int half = n >>> 1;
            while (k < half) {
    
    //如果还有儿子节点
                int child = (k << 1) + 1;//左儿子下标
                Object c = array[child];
                int right = child + 1;//右儿子下标
                //如果右儿子比左儿子更满足排序规则,就将c设置为右儿子
                if (right < n && cmp.compare((T) c, (T) array[right]) > 0)
                    c = array[child = right];
                //如果两个儿子和parent相比都不满足规则,就退出循环,向下堆化结束
                if (cmp.compare(x, (T) c) <= 0)
                    break;
                array[k] = c; //如果儿子节点满足排序规则,就将儿子节点挪到父亲节点上 
                k = child;
            }
            array[k] = x;
        }
    }

向下堆化,就是从左儿子和右儿子之中挑出符合排序规则的点与parent调换,然后再将被调换的儿子节点作为parent节点继续执行这个过程,直至符合排序规则

猜你喜欢

转载自blog.csdn.net/qq_15604349/article/details/124636635