[concurrency-interest] Can this be done with ConcurrentHashMap ?

Tim Peierls tim@peierls.net
Thu, 23 Dec 2004 11:50:37 -0500


Donnie Hale wrote:
> Assuming what I want to do is clear, is this possible with a
> ConcurrentHashMap?

Here's a general solution that uses ConcurrentHashMap that you
can adapt for your purposes. This is code that Joe Bowbeer wrote
and presented at a JavaOne talk; I don't think there are any
limitations on its use. (Joe, speak up if you think there might be.)

public interface Computable<A, V> {
     V compute(A arg) throws Exception;
}

public class Memoize<A, V> implements Computable<A, V> {
     public Memoize(Computable<A, V> c) {
         this.c = c;
     }
     public V compute(final A arg) throws Exception {
         Future<V> f = cache.get(arg);
         if (f == null) {
             Callable<V> eval = new Callable<V>() {
                 public V call() throws Exception {
                     return c.compute(arg);
                 }
             };
             FutureTask<V> ft = new FutureTask<V>(eval);
             f = cache.putIfAbsent(arg, ft);
             if (f == null) { f = ft; ft.run(); }
         }
         return f.get();
     }
     private final ConcurrentMap<A, Future<V>> cache =
         new ConcurrentHashMap<A, Future<V>>();
     private final Computable<A, V> c;
}

You would use this as follows:

   class MyLengthyOperation implements Computable<Key, Value> {
       public Value compute(Key key) {
           // Lengthy operation here, takes key and returns
           // a value.
       }
   }

   // instead of map:
   Computable<Key, Value> map =
       new Memoize<Key, Value>(new MyLengthyOperation());

   // and then you can get values:

   for (Key key : interestingKeys) {
       Value value = map.compute(key);
       // do something with value
   }

--tim