Java PriorityQueue:轮询()然后添加()或peek()然后删除()更好吗

Java PriorityQueue:轮询()然后添加()或peek()然后删除()更好吗,java,performance,collections,queue,Java,Performance,Collections,Queue,我刚刚完成了我的网络作业队列,我有一个关于Java中优先级队列性能的小问题 以这个代码为例: private void performJob() { lock.lock(); try { NetworkJob job = actions.poll(); if (job.perform()) { return; } actions.add(job); //Job was a failure,

我刚刚完成了我的网络作业队列,我有一个关于Java中优先级队列性能的小问题

以这个代码为例:

 private void performJob() {
    lock.lock();
    try {
        NetworkJob job = actions.poll();
        if (job.perform()) {
            return;
        }
        actions.add(job); //Job was a failure, add it back to the queue
    } finally {
        lock.unlock();
    }
}
在作业失败的情况下,作业仍然需要在队列中。那么,我的问题是:
poll()
然后
add()
还是
peek()
然后
remove()

我个人倾向于下面的代码,但考虑到一份工作不应该真的失败(在大多数情况下,假设它是通过的),只进行
poll()
是否更好

完全是吹毛求疵,可能不值得担心,因为队列很少使用,但这让我感兴趣,我想看看你的推理

完整代码:

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.util.Log;

import java.util.PriorityQueue;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

public final class NetworkQueue implements Runnable {

    private final Context context;
    private final AtomicBoolean running = new AtomicBoolean(true);
    private final PriorityQueue<NetworkJob> actions = new PriorityQueue<>(5, new NetworkJobComparator());
    private final ReentrantLock lock = new ReentrantLock();
    private final Condition jobReady = lock.newCondition();
    private final Condition networkUp = lock.newCondition();

    private ConnectionType connection = ConnectionType.NONE;

    public NetworkQueue(Context context) {
        this.context = context;
        context.registerReceiver(new NetworkListener(),
                new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
    }

    @Override
    public void run() {
        try {
            while (running.get()) {
                waitJobAvailable();
                waitNetworkUp();
                performJob();
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    private void setNetwork(ConnectionType net) {
        lock.lock();
        try {
            connection = net;
            if (connection != ConnectionType.NONE) {
                networkUp.signal();
            }
        } finally {
            lock.unlock();
        }
    }

    private void waitNetworkUp() throws InterruptedException {
        lock.lock();
        try {
            while (connection != ConnectionType.NONE) {
                networkUp.await();
            }
        } finally {
            lock.unlock();
        }
    }


    private void waitJobAvailable() throws InterruptedException {
        lock.lock();
        try {
            while (actions.isEmpty()) {
                jobReady.await();
            }
        } finally {
            lock.unlock();
        }
    }

    private void performJob() {
        lock.lock();
        try {
            NetworkJob job = actions.peek();
            if (!job.perform()) {
                return;
            }
            actions.remove();
        } finally {
            lock.unlock();
        }
    }

    public boolean addJob(NetworkJob job) {
        lock.lock();
        try {
            if (this.actions.contains(job)) {
                return false;
            }
            this.actions.add(job);
            this.jobReady.signal();
            return true;
        } finally {
            lock.unlock();
        }
    }

    public void end() {
        this.running.set(false);
    }

    private class NetworkListener extends BroadcastReceiver {

        ConnectivityManager conn = (ConnectivityManager)
                context.getSystemService(Context.CONNECTIVITY_SERVICE);

        @Override
        public void onReceive(Context context, Intent intent) {
            NetworkInfo networkInfo = conn.getActiveNetworkInfo();
            if (networkInfo == null) {
                setNetwork(ConnectionType.NONE);
                return;
            }
            if (networkInfo.getType() == ConnectivityManager.TYPE_WIFI) {
                setNetwork(ConnectionType.WIFI);
                return;
            }
            setNetwork(ConnectionType.ANY);
        }
    }

}
导入android.content.BroadcastReceiver;
导入android.content.Context;
导入android.content.Intent;
导入android.content.IntentFilter;
导入android.net.ConnectivityManager;
导入android.net.NetworkInfo;
导入android.util.Log;
导入java.util.PriorityQueue;
导入java.util.concurrent.AtomicBoolean;
导入java.util.concurrent.locks.Condition;
导入java.util.concurrent.locks.ReentrantLock;
公共最终类NetworkQueue实现可运行{
私人最终语境;
private final AtomicBoolean running=新的AtomicBoolean(true);
private final PriorityQueue actions=new PriorityQueue(5,new NetworkJobComparator());
private final ReentrantLock lock=new ReentrantLock();
私有最终条件jobReady=lock.newCondition();
私有最终条件networkUp=lock.newCondition();
私有ConnectionType连接=ConnectionType.NONE;
公用网络队列(上下文){
this.context=上下文;
context.registerReceiver(新的NetworkListener(),
新的IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
}
@凌驾
公开募捐{
试一试{
(运行.get()时){
waitJobAvailable();
waitNetworkUp();
performJob();
}
}捕捉(中断异常e){
e、 printStackTrace();
}
}
专用网络(连接类型网络){
lock.lock();
试一试{
连接=网络;
if(连接!=ConnectionType.NONE){
networkUp.signal();
}
}最后{
lock.unlock();
}
}
私有void waitNetworkUp()引发InterruptedException{
lock.lock();
试一试{
while(连接!=ConnectionType.NONE){
networkUp.wait();
}
}最后{
lock.unlock();
}
}
private void waitJobAvailable()引发InterruptedException{
lock.lock();
试一试{
while(actions.isEmpty()){
jobReady.wait();
}
}最后{
lock.unlock();
}
}
私人公司{
lock.lock();
试一试{
NetworkJob作业=actions.peek();
如果(!job.perform()){
返回;
}
动作。移除();
}最后{
lock.unlock();
}
}
公共布尔addJob(网络作业){
lock.lock();
试一试{
if(this.actions.contains(作业)){
返回false;
}
this.actions.add(作业);
this.jobReady.signal();
返回true;
}最后{
lock.unlock();
}
}
公共无效结束(){
this.running.set(false);
}
私有类NetworkListener扩展了BroadcastReceiver{
ConnectionManager连接=(ConnectionManager)
getSystemService(context.CONNECTIVITY\u服务);
@凌驾
公共void onReceive(上下文、意图){
NetworkInfo NetworkInfo=conn.getActiveNetworkInfo();
if(networkInfo==null){
setNetwork(ConnectionType.NONE);
返回;
}
if(networkInfo.getType()==ConnectivityManager.TYPE\u WIFI){
setNetwork(ConnectionType.WIFI);
返回;
}
setNetwork(ConnectionType.ANY);
}
}
}

在OpenJDK和OracleJDK中基于堆的标准
PriorityQueue
实现中,
peek()
调用速度极快:

public E peek() {
    return (size == 0) ? null : (E) queue[0];
}
这是因为堆根总是最小的元素。相比之下,删除和添加操作可能非常昂贵,因为它们可能需要重新构造堆。因此,
peek/remove
解决方案可能更快


在我的库中,我有一个算法可以从未排序的输入中选择
n
最少的元素。我使用
PriorityQueue
实现它,它最多保留
n
到目前为止发现的最少元素。第一个实现类似于
add/poll
。当我使用
peek
时,性能得到了极大的提高(在某些测试中提高了10倍)。

就性能而言,这可能(甚至可能主要)取决于您使用的队列的确切实现。除此之外,您应该注意,除非代码段仅用于单线程,否则它们具有不同的语义。@Marco13我对代码段进行了一些扩展,以显示队列作为一个整体是多线程的,但代码块是锁定的。语义不同是什么意思?如果代码段没有被锁定(如在编辑的版本中),那么同时执行代码段的两个线程将
poll
不同的元素(在第一个版本中),或者
peek
(在第二个版本中)。这一点现在很清楚,但仍然是:这是一个阻塞队列吗?特别是,
PriorityBlockingQueue
?@Marco13表示歉意。不,这是优先权
public E peek() {
    return (size == 0) ? null : (E) queue[0];
}