PriorityQueue和PriorityBlockingQueue

时间:2013-05-22 13:38:36

标签: java java.util.concurrent

我应该在这些程序中选择哪一个以及为什么?一般来说,问题是为什么我应该选择使用PriorityBlockingQueue优先于PriorityQueue。

的PriorityBlockingQueue

import java.util.concurrent.PriorityBlockingQueue;

public class PriorityBlockingQueueExample {

    static PriorityBlockingQueue<String> priorityQueue = new PriorityBlockingQueue<String>();
    public static void main(String[] args) {

        new Thread(){
            public void run(){
                try {
                System.out.println(priorityQueue.take() +" is removed from priorityQueue object");
                } catch (InterruptedException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }    
            }
        }.start();
        new Thread(){
            public void run(){
                priorityQueue.add("string variable");
                System.out.println("Added an element to the queue");
            }
        }.start();
    }
}

我应该在这些程序中选择哪一个以及为什么?一般来说问题是为什么我应该选择使用PriorityBlockingQueue优先于PriorityQueue。 的PriorityQueue

import java.util.PriorityQueue;

public class PriorityQueueTest {

    static PriorityQueue<String> priorityQueue = new PriorityQueue<String>();
    private static Object lock = new Object();
    public static void main(String[] args) {

        new Thread(){
            public void run(){
                synchronized(lock){     
                    try {
                        while(priorityQueue.isEmpty()){lock.wait();}
                            System.out.println(priorityQueue.remove() +" is removed from priorityQueue object");
                            lock.notify();
                    } catch (InterruptedException e) {
                            //  TODO Auto-generated catch block
                            e.printStackTrace();
                    }
                }
            }
        }.start();
        new Thread(){
            public void run(){
                synchronized(lock){
                    priorityQueue.add("string variable");
                    System.out.println("Added an element to the queue");
                    lock.notify();
                }
            }
        }.start();
    }
}

3 个答案:

答案 0 :(得分:15)

正常Queue在访问时会返回null,如果它是空的,而BlockingQueue 阻止,如果队列为空,直到值可用。

您正在使用的队列中的优先级部分仅表示按特定顺序从队列中读取项目(如果它们实现Comparable或根据{{1 }})。

通常,您可以依赖抽象类型ComparatorPriorityQueue。如果您的代码需要了解这两个概念,则可能需要重新考虑。

有许多原因导致您需要BlockingQueue归结为消息排序。例如,在作业队列中,您可能希望能够优先处理这些作业。这通常表示处理作业的代码应该与订单无关。

对于PriorityQueue,您通常在工作线程领域进行排队工作,当没有工作要做时,可以阻止这些线程直到工作可用。与BlockingQueue的示例类似,调用代码可能与此无关,但是您可能希望使用某种等待超时并非总是如此。

答案 1 :(得分:8)

在JDK 5中添加了并发包的PriorityBlockingQueue,请参阅:http://docs.oracle.com/javase/1.5.0/docs/api/java/util/concurrent/package-summary.html

它基本上是在为你的队列添加通常必要的同步/等待/通知而为PriorityQueue编写的额外代码。因此,添加名称的“阻塞”部分意味着线程将阻止等待,直到队列中有可用的项目为止。

如果您的应用可以在JDK 5或更高版本上运行,我会使用PriorityBlockingQueue。

答案 2 :(得分:1)

我知道这是一个老话题,但我看到你没有考虑优先级队列的并发实现。

尽管java的集合框架没有,但它确实有足够的构建块来创建一个:

public class ConcurrentSkipListPriorityQueue<T> implements Queue<T> {

    private ConcurrentSkipListMap<T, Boolean> values;

    public ConcurrentSkipListPriorityQueue(Comparator<? super T> comparator) {
        values = new ConcurrentSkipListMap<>(comparator);
    }

    public ConcurrentSkipListPriorityQueue() {
        values = new ConcurrentSkipListMap<>();
    }

    @Override
    public boolean add(T e) {
        values.put(e, Boolean.TRUE);
        return true;
    }

    @Override
    public boolean offer(T e) {
        return add(e);
    }

    @Override
    public T remove() {
        while (true) {
            final T v = values.firstKey();
            if (values.remove(v)) {
                return v;
            }
        }
    }

    @Override
    public T poll() {

        try {
            while (true) {
                if (values.isEmpty()) {
                    return null;
                }
                final T v = values.firstKey();
                if (values.remove(v)) {
                    return v;
                }
            }
        } catch (NoSuchElementException ex) {
            return null; // poll should not throw an exception.. 
        }
    }

    @Override
    public T element() {
        return values.firstKey();
    }

    @Override
    public T peek() {
        if (values.isEmpty()) {
            return null;
        }

        try {
            return element();
        } catch (NoSuchElementException ex) {
            return null;
        }
    }

    @Override
    public int size() {
        return values.size();
    }

    @Override
    public boolean isEmpty() {
        return values.isEmpty();
    }

    @Override
    public boolean contains(Object o) {
        return values.containsKey(o);
    }

    @Override
    public Iterator<T> iterator() {
        return values.keySet().iterator();
    }

    @Override
    public Object[] toArray() {
        return values.keySet().toArray();
    }

    @Override
    public <T> T[] toArray(T[] a) {
        return values.keySet().toArray(a);
    }

    @Override
    public boolean remove(Object o) {
        return values.remove(o);
    }

    @Override
    public boolean containsAll(Collection<?> c) {
        return values.keySet().containsAll(c);
    }

    @Override
    public boolean addAll(Collection<? extends T> c) {

        boolean changed = false;

        for (T i : c) {
            changed |= add(i);
        }

        return changed;
    }

    @Override
    public boolean removeAll(Collection<?> c) {
        return values.keySet().removeAll(c);
    }

    @Override
    public boolean retainAll(Collection<?> c) {
        return values.keySet().retainAll(c);
    }

    @Override
    public void clear() {
        values.clear();
    }

}

此队列基于跳过列表,将其所有操作委派给ConcurrentSkipListMap类。它允许来自多个线程的非阻塞并发访问。