Hot questions for Cache Listerner in Guava

Top 10 Java Open Source / Guava / Cache Listerner

Guava cache listener for insertions

Question: We'd find it very useful to have an AddListener to complement RemovalListener in Google Guava.

Is there a suitable alternative to an AddListener that would complement RemovalListener?

Answer: You can provide that yourself - just pass your custom listener to your computing Function, and whenever you compute a value, notify the listener.

If you are using asMap().put(..), then you'd have to wrap the whole thing in in your custom classes that delegate to the originals but also invoke the addition listener.


ListenableFuture, FutureCallback and timeouts

Question: Based on the examples of guava I've been looking for elegant solutions to my problem. Specifically, I like the way Futures.addCallback(ListenableFuture, FutureCallback) works, but I'd like to be able to set a timeout on the length of time that can expire before the FutureCallback is invoked. Optimally It would be nice if breaching the timeout just caused an the failure condition of FutureCallback to be called.

Does Guava have something like this already? Is it just not recommended to try to couple timeouts with the callbacks?

Answer: Internally, we have a makeTimeoutFuture method that takes a Future as input and returns a new Future that will have the same result unless the original hasn't completed by a given deadline. If the deadline expires, the output Future has its result set to a TimeoutException. So, you could call makeTimeoutFuture and attach listeners to the output Future.

makeTimeoutFuture isn't the most natural solution for your problem. In fact, I think that the method was created primarily to set a hard timeout on no-arg get() calls, since it can be a pain to propagate the desired deadline to all callers. A more natural solution is to reason that get() is to get(long, TimeUnit) as addCallback(ListenableFuture, FutureCallback) is to addCallback(ListenableFuture, FutureCallback, long, TimeUnit, SchededuledExecutorService). That's a little clumsy, albeit less so than makeTimeoutFuture.

Here's what we have internally:

public static <V> ListenableFuture<V> makeTimeoutFuture(
    ListenableFuture<V> delegate,
    Duration duration,
    ScheduledExecutorService scheduledExecutor)

Returns a future that delegates to another but will finish early (via a TimeoutException wrapped in an ExecutionException) if the specified duration expires. The delegate future is not cancelled in this case.

scheduledExecutor.schedule(new Runnable() {
  @Override public void run() {
    TimeoutFuture.this.setException(new TimeoutException("Future timed out"));
  }
}, duration.getMillis(), TimeUnit.MILLISECONDS);

Use the results of two Guava ListenableFutures of different types

Question: I have two ListenableFutures which are completed on other threads. Each future is of a different type, and I wish to use both of their results when they are both complete.

Is there an elegant way to handle this using Guava?

Answer: If you want some sort of type safety you can do the following:

class Composite {
  public A a;
  public B b;
}

public ListenableFuture<Composite> combine(ListenableFuture<A> futureA, 
                                           final ListenableFuture<B> futureB) {

  return Futures.transform(futureA, new AsyncFunction<A, Composite>() {
    public ListenableFuture<Composite> apply(final A a) throws Exception {
      return Futures.transform(futureB, new Function<B, Compisite>() {
        public Composite apply(B b) {
          return new Composite(a, b);
        }
      }
    } 
  }

}

ListenableFuture<A> futureA = ...
ListenableFuture<B> futureB = ...

ListenableFuture<Composite> result = combine(futureA, futureB);

In this case Composite can be a Pair<A, B> from Apache Commons if you like.

Also, a failure in either future will result in a failure in the resulting combined future.