2

I've found DelayQueue, which is exactly what I need. In general, I agree that a ScheduledExecutorService is better, but I already have an executor and I want full control of the timing.

So I have to implement the Delayed interface. This forced me to add clock (an instance of my tiny wrapper around java.time.Clock), so I get the current time:

private final Instant expires;
private final Clock clock; // UGLY!!!

public long getDelay(TimeUnit timeUnit) {
    return timeUnit.convert(
            Duration.between(expires, clock.now()).toNanos(),
            TimeUnit.NANOSECONDS);
}

Now I need to implement Comparable<Delayed>, i.e., to compare instances of my class to any instance of Delayed. I guess that

public int compareTo(Delayed that) {
   return instant.compareTo(((MyClass) that).instant);
}

would lead to a ClassCastException somewhere. The other possibility is using

public int compareTo(Delayed that) {
    return Long.compare(
          this.getDelay(TimeUnit.NANOSECOND),
          that.getDelay(TimeUnit.NANOSECOND));
}

But such a method could have been implemented in the interface (there's nothing specific to my class there) or simply omitted as the queue could use a corresponding Comparator.

Moreover, as getDelay depends on the current time, it's not possible to implement the method really correctly as some time passes between the invocations. For example, myInstance.compareTo(myInstance) would return non-zero because of this. This case can be easily countered by testing this==that first, however I can't see any general solution (apart from some ugly ThreadLocal hack).

What am I missing?

maaartinus
  • 44,714
  • 32
  • 161
  • 320
  • Why do you need to implement `Comparable`? I might be missing it, but I don't see that `DelayQueue` requires it. – daniu Mar 28 '18 at 09:29
  • 2
    @daniu `Delayed` extends `Comparable`. – Kayaman Mar 28 '18 at 09:31
  • Huh, so I did miss it. Well looking at JDK code of implementors of the interface, subtracting the `getDelay`-results is what it boils down to... – daniu Mar 28 '18 at 10:02
  • 1
    @daniu Agreed, I should've looked at it first. However, it's not really correct, is it? – maaartinus Mar 28 '18 at 10:46
  • @maaartinus It's not. It probably doesn't really matter in practice because the comparison operation only happens upon insertion into the queue (to keep it sorted), so a few milliseconds difference is not an issue. – daniu Mar 28 '18 at 10:50
  • 1
    @daniu I'm not sure. The underlying data structure is a `PriorityQueue`. By blowing up the comparison, you lose the heap property. I guess, any inconsistency may affect also unrelated entries. However, I believe that small variations in `getDelay` would cause only small errors, i.e., returning entries in wrong order, but only if they're close to each other. Still this would need some analysis rather than guesswork. – maaartinus Apr 01 '18 at 03:43

0 Answers0