简体   繁体   English

Java非阻塞DelayQueue

[英]Nonblocking DelayQueue, Java

I'm using Java's DelayQueue to dispatch events after a second delay. 我正在使用Java的DelayQueue在第二次延迟后调度事件。 But the problem is that, under heavy load, my consumers on DelayQueue block until considerable bulk of offer() operations from another threads are gone. 但是问题是,在高负载下,我的使用者在DelayQueue上阻塞,直到其他线程的大部分offer()操作都消失了。

Does anyone know non-blocking delay queue implementations in Java? 有谁知道Java中的非阻塞延迟队列实现?

I think you are misunderstanding either the DelayQueue API or the way that thread scheduling works. 我认为您误解了DelayQueue API或线程调度的工作方式。

If you want genuine non-blocking queue operations, then DelayQueue already provides them. 如果您想要真正的非阻塞队列操作,那么DelayQueue已经提供了它们。 For example poll() will immediately return either a queue entry or null . 例如poll()将立即返回队列条目或null It won't block the calling thread. 它不会阻塞调用线程。 The offer(...) method is the equivalent method for inserting without blocking. offer(...)方法是无阻塞插入的等效方法。

On the other hand, if you are actually saying that some threads are being "starved", then there is not much you can do about that. 另一方面,如果您实际上是在说某些线程正在“饥饿”,那么您将无能为力。 Java thread scheduling is not "fair": Java线程调度不公平:

  • If you have lots of threads that are runnable, no attempt is made to give each one a similar amount of run time. 如果您有许多可运行的线程,则不会尝试为每个线程分配相似的运行时间。

  • If you have multiple threads waiting on a primitive lock or notify, then the scheduler won't make any attempt to pick one thread "fairly". 如果您有多个线程在等待原始锁或通知,则调度程序将不会尝试“公平地”选择一个线程。

Thread starvation is going to be more likely if you have lots more threads than you have cores to run them. 如果线程数量多于运行内核的数量,那么线程饥饿的可能性就会更大。

The best solution is to design your algorithms such that it doesn't matter if threads are scheduled unfairly. 最好的解决方案是设计算法,以使线程的调度是否不重要都无关紧要。 It shouldn't matter; 没关系; see Is a DelayQueue without fairness problematic? 请参见没有公平性的DelayQueue有问题吗? .


For the record, I'm not aware of a DelayQueue replacement that advertises fair scheduling. 作为记录,我不知道有一个DelayQueue替代品来宣传合理的调度。

Unfortunately, DelayQueue is blocking queue and it doesn't return immediately if it's intensely being written to because it uses a lock. 不幸的是,DelayQueue阻塞了队列,如果由于使用锁而被强烈写入,它不会立即返回。

public E poll() {
    final ReentrantLock lock = this.lock;
    lock.lock();
    try {
        E first = q.peek();
        if (first == null || first.getDelay(NANOSECONDS) > 0)
            return null;
        else
            return q.poll();
    } finally {
        lock.unlock();
    }
}

So if many threads write to it, as Stephen said, there is not much you can do about that. 因此,如Stephen所言,如果有许多线程对其进行写操作,那么您将无能为力。

I solved the problem by using ConcurrentSkipListSet with DelayedElement. 我通过将ConcurrentSkipListSet与DelayedElement一起使用解决了这个问题。

public class DelayedElement implements Comparable<DelayedElement> {

private final Long initTime;
private final String msgId;

public DelayedElement(Long initTime, String msgId) {
    this.initTime = initTime;
    this.msgId = msgId;
}             

@Override
public int hashCode() {
    int hash = 5;
    hash = 29 * hash + Objects.hashCode(this.initTime);
    hash = 29 * hash + Objects.hashCode(this.msgId);
    return hash;
}

@Override
public boolean equals(Object obj) {
    if (obj == null) {
        return false;
    }
    if (getClass() != obj.getClass()) {
        return false;
    }
    final DelayedElement other = (DelayedElement) obj;
    if (!Objects.equals(this.initTime, other.initTime)) {
        return false;
    }
    if (!Objects.equals(this.msgId, other.msgId)) {
        return false;
    }
    return true;
}
@Override
public int compareTo(DelayedElement o) {
    return -o.initTime.compareTo(initTime);
    }
}

In my producers' threads, I add each element with a second's delay. 在生产者线程中,我将每个元素添加一秒钟的延迟。 In my consumer thread, I simply read elements which has a second's delay like: 在我的使用者线程中,我只读取了延迟一秒钟的元素,例如:

 long diff = System.nanoTime() - TimeUnit.MILLISECONDS.toNanos(1000L);
 NavigableSet<DelayedElement> set = queue.headSet(
 new DelayedElement(diff, "", null));
 //further processing goes here     

This way I achieve non-blocking nature and can safely write and read from the Collection at full throttle. 这样,我就可以实现非阻塞性,并且可以全速安全地从Collection中进行读写。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM