优先级对列PriorityBlockingQueue

    xiaoxiao2021-04-16  30

    PriorityBlockingQueue里面存储的对象必须是实现Comparable接口。队列通过这个接口的compare方法确定对象的priority。 规则是:当前和其他对象比较,如果compare方法返回负数,那么在队列里面的优先级就比较搞。 下面的测试可以说明这个断言: 查看打印结果,比较take出来的Entity和left的entity,比较他们的priority

    package com.java.exam1;

    import java.util.Random; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.PriorityBlockingQueue; import java.util.concurrent.TimeUnit;

    public class TestPriorityQueue {           static Random r=new Random(47);              public static void main(String args[]) throws InterruptedException{           final PriorityBlockingQueue q=new PriorityBlockingQueue();           ExecutorService se=Executors.newCachedThreadPool();           //execute producer           se.execute(new Runnable(){               public void run() {                   int i=0;                   while(true){                       q.put(new PriorityEntity(r.nextInt(10),i++));                       try {                           TimeUnit.MILLISECONDS.sleep(r.nextInt(1000));                       } catch (InterruptedException e) {                           // TODO Auto-generated catch block                           e.printStackTrace();                       }                   }               }           });                     //execute consumer           se.execute(new Runnable(){               public void run() {                   while(true){                       try {                           System.out.println("take-- "+q.take()+" left:-- ["+q.toString()+"]");                           try {                              TimeUnit.MILLISECONDS.sleep(r.nextInt(1000));                           } catch (InterruptedException e) {                               // TODO Auto-generated catch block                               e.printStackTrace();                           }                       } catch (InterruptedException e) {                           e.printStackTrace();                       }                   }               }           });           try {               TimeUnit.SECONDS.sleep(5);           } catch (InterruptedException e) {               // TODO Auto-generated catch block               e.printStackTrace();           }           System.out.println("shutdown");       }     }     class PriorityEntity implements Comparable<PriorityEntity> {       private static int count=0;       private int id=count++;       private int priority;       private int index=0;         public PriorityEntity(int _priority,int _index) {           this.priority = _priority;           this.index=_index;       }              public String toString(){           return id+"# [index="+index+" priority="+priority+"]";       }         //数字小,优先级高       public int compareTo(PriorityEntity o) {           return this.priority > o.priority ? 1                  : this.priority < o.priority ? -1 : 0;       }         //数字大,优先级高   //  public int compareTo(PriorityTask o) {   //      return this.priority < o.priority ? 1   //              : this.priority > o.priority ? -1 : 0;   //  }   } 

     

    问题:有没有人在使用时,发现将添加在PriorityBlockingQueue的一系列元素打印出来,队列的元素其实并不是全部按优先级排序的,但是队列头的优先级肯定是最高的?

    回复:PriorityBlockingQueue队列添加新元素时候不是将全部元素进行顺序排列,而是从某个指定位置开始将新元素与之比较,一直比到队列头,这样既能保证队列头一定是优先级最高的元素,又能减少排序带来的性能消耗(个人判断,仅供参考),可以查看PriorityBlockingQueue源码,添加元素有调用一个方法是PriorityQueue.siftUpUsingComparator(或siftUpComparable),这个方法里有个排序算法:

    private void siftUpComparable(int k, E x) {         Comparable<? super E> key = (Comparable<? super E>) x;         while (k > 0) {             int parent = (k - 1) >>> 1;             Object e = queue[parent];             if (key.compareTo((E) e) >= 0)                 break;             queue[k] = e;             k = parent;         }         queue[k] = key;     }

    不是全部排序。

    但是这样会出现一个情况,取完队列头时候,后面的剩余的元素不是排序的,岂不是不符合要求了,继续查看源码,发现每取一个头元素时候,都会对剩余的元素做一次调整,这样就能保证每次队列头的元素都是优先级最高的元素,查看取元素时候调用的一个方法PriorityQueue.:

     private void siftDown(int k, E x) {         if (comparator != null)             siftDownUsingComparator(k, x);         else             siftDownComparable(k, x);     }

     private void siftDownUsingComparator(int k, E x) {         int half = size >>> 1;         while (k < half) {             int child = (k << 1) + 1;             Object c = queue[child];             int right = child + 1;             if (right < size &&                 comparator.compare((E) c, (E) queue[right]) > 0)                 c = queue[child = right];             if (comparator.compare(x, (E) c) <= 0)                 break;             queue[k] = c;             k = child;         }         queue[k] = x;     }

    转载请注明原文地址: https://ju.6miu.com/read-672985.html

    最新回复(0)