gpt4 book ai didi

Java 优先级队列 : Is it better to poll() and then add() or peek() and then remove()

转载 作者:行者123 更新时间:2023-12-01 11:06:23 24 4
gpt4 key购买 nike

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

获取此代码:

 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()

 private void performJob() {
lock.lock();
try {
NetworkJob job = actions.peek();
if (!job.perform()) {
return;
}
actions.remove(); //Job was a success, we can remove it from the queue.
} finally {
lock.unlock();
}
}

完全是吹毛求疵,由于队列很少使用,可能不值得担心,但它引起了我的兴趣,我想看看你的推理。

完整代码:

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

}

最佳答案

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

public E peek() {
return (size == 0) ? null : (E) queue[0];
}

这是因为堆根始终是最小元素。相反,删除和添加操作可能非常昂贵,因为它们可能需要重组堆。因此peek/remove解决方案可能会更快。

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

关于Java 优先级队列 : Is it better to poll() and then add() or peek() and then remove(),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32904405/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com