Home | History | Annotate | Download | only in collect
      1 /*
      2  * Copyright (C) 2009 Google Inc.
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  * http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.google.common.collect;
     18 
     19 import com.google.common.annotations.GwtCompatible;
     20 import com.google.common.annotations.GwtIncompatible;
     21 import com.google.common.base.FinalizableReferenceQueue;
     22 import com.google.common.base.FinalizableSoftReference;
     23 import com.google.common.base.FinalizableWeakReference;
     24 import com.google.common.base.Function;
     25 import com.google.common.collect.CustomConcurrentHashMap.ComputingStrategy;
     26 import com.google.common.collect.CustomConcurrentHashMap.Internals;
     27 
     28 import java.io.IOException;
     29 import java.io.ObjectInputStream;
     30 import java.io.ObjectOutputStream;
     31 import java.io.Serializable;
     32 import java.lang.ref.SoftReference;
     33 import java.lang.ref.WeakReference;
     34 import java.lang.reflect.Field;
     35 import java.util.Map;
     36 import java.util.TimerTask;
     37 import java.util.concurrent.ConcurrentHashMap;
     38 import java.util.concurrent.ConcurrentMap;
     39 import java.util.concurrent.TimeUnit;
     40 
     41 /**
     42  * A {@link ConcurrentMap} builder, providing any combination of these
     43  * features: {@linkplain SoftReference soft} or {@linkplain WeakReference
     44  * weak} keys, soft or weak values, timed expiration, and on-demand
     45  * computation of values. Usage example: <pre> {@code
     46  *
     47  *   ConcurrentMap<Key, Graph> graphs = new MapMaker()
     48  *       .concurrencyLevel(32)
     49  *       .softKeys()
     50  *       .weakValues()
     51  *       .expiration(30, TimeUnit.MINUTES)
     52  *       .makeComputingMap(
     53  *           new Function<Key, Graph>() {
     54  *             public Graph apply(Key key) {
     55  *               return createExpensiveGraph(key);
     56  *             }
     57  *           });}</pre>
     58  *
     59  * These features are all optional; {@code new MapMaker().makeMap()}
     60  * returns a valid concurrent map that behaves exactly like a
     61  * {@link ConcurrentHashMap}.
     62  *
     63  * The returned map is implemented as a hash table with similar performance
     64  * characteristics to {@link ConcurrentHashMap}. It supports all optional
     65  * operations of the {@code ConcurrentMap} interface. It does not permit
     66  * null keys or values. It is serializable; however, serializing a map that
     67  * uses soft or weak references can give unpredictable results.
     68  *
     69  * <p><b>Note:</b> by default, the returned map uses equality comparisons
     70  * (the {@link Object#equals(Object) equals} method) to determine equality
     71  * for keys or values. However, if {@link #weakKeys()} or {@link
     72  * #softKeys()} was specified, the map uses identity ({@code ==})
     73  * comparisons instead for keys. Likewise, if {@link #weakValues()} or
     74  * {@link #softValues()} was specified, the map uses identity comparisons
     75  * for values.
     76  *
     77  * <p>The returned map has <i>weakly consistent iteration</i>: an iterator
     78  * over one of the map's view collections may reflect some, all or none of
     79  * the changes made to the map after the iterator was created.
     80  *
     81  * <p>An entry whose key or value is reclaimed by the garbage collector
     82  * immediately disappears from the map. (If the default settings of strong
     83  * keys and strong values are used, this will never happen.) The client can
     84  * never observe a partially-reclaimed entry. Any {@link java.util.Map.Entry}
     85  * instance retrieved from the map's {@linkplain Map#entrySet() entry set}
     86  * is snapshot of that entry's state at the time of retrieval.
     87  *
     88  * <p>{@code new MapMaker().weakKeys().makeMap()} can almost always be
     89  * used as a drop-in replacement for {@link java.util.WeakHashMap}, adding
     90  * concurrency, asynchronous cleanup, identity-based equality for keys, and
     91  * great flexibility.
     92  *
     93  * @author Bob Lee
     94  * @author Kevin Bourrillion
     95  * @since 2010.01.04 <b>stable</b> (imported from Google Collections Library)
     96  */
     97 @GwtCompatible(emulated = true)
     98 public final class MapMaker {
     99   private Strength keyStrength = Strength.STRONG;
    100   private Strength valueStrength = Strength.STRONG;
    101   private long expirationNanos = 0;
    102   private boolean useCustomMap;
    103   private final CustomConcurrentHashMap.Builder builder
    104       = new CustomConcurrentHashMap.Builder();
    105 
    106   /**
    107    * Constructs a new {@code MapMaker} instance with default settings,
    108    * including strong keys, strong values, and no automatic expiration.
    109    */
    110   public MapMaker() {}
    111 
    112   /**
    113    * Sets a custom initial capacity (defaults to 16). Resizing this or
    114    * any other kind of hash table is a relatively slow operation, so,
    115    * when possible, it is a good idea to provide estimates of expected
    116    * table sizes.
    117    *
    118    * @throws IllegalArgumentException if {@code initialCapacity} is
    119    *   negative
    120    * @throws IllegalStateException if an initial capacity was already set
    121    */
    122   public MapMaker initialCapacity(int initialCapacity) {
    123     builder.initialCapacity(initialCapacity);
    124     return this;
    125   }
    126 
    127   /**
    128    * Guides the allowed concurrency among update operations. Used as a
    129    * hint for internal sizing. The table is internally partitioned to try
    130    * to permit the indicated number of concurrent updates without
    131    * contention.  Because placement in hash tables is essentially random,
    132    * the actual concurrency will vary. Ideally, you should choose a value
    133    * to accommodate as many threads as will ever concurrently modify the
    134    * table. Using a significantly higher value than you need can waste
    135    * space and time, and a significantly lower value can lead to thread
    136    * contention. But overestimates and underestimates within an order of
    137    * magnitude do not usually have much noticeable impact. A value of one
    138    * is appropriate when it is known that only one thread will modify and
    139    * all others will only read. Defaults to 16.
    140    *
    141    * @throws IllegalArgumentException if {@code concurrencyLevel} is
    142    *     nonpositive
    143    * @throws IllegalStateException if a concurrency level was already set
    144    */
    145   @GwtIncompatible("java.util.concurrent.ConcurrentHashMap concurrencyLevel")
    146   public MapMaker concurrencyLevel(int concurrencyLevel) {
    147     builder.concurrencyLevel(concurrencyLevel);
    148     return this;
    149   }
    150 
    151   /**
    152    * Specifies that each key (not value) stored in the map should be
    153    * wrapped in a {@link WeakReference} (by default, strong references
    154    * are used).
    155    *
    156    * <p><b>Note:</b> the map will use identity ({@code ==}) comparison
    157    * to determine equality of weak keys, which may not behave as you expect.
    158    * For example, storing a key in the map and then attempting a lookup
    159    * using a different but {@link Object#equals(Object) equals}-equivalent
    160    * key will always fail.
    161    *
    162    * @throws IllegalStateException if the key strength was already set
    163    * @see WeakReference
    164    */
    165   @GwtIncompatible("java.lang.ref.WeakReference")
    166   public MapMaker weakKeys() {
    167     return setKeyStrength(Strength.WEAK);
    168   }
    169 
    170   /**
    171    * Specifies that each key (not value) stored in the map should be
    172    * wrapped in a {@link SoftReference} (by default, strong references
    173    * are used).
    174    *
    175    * <p><b>Note:</b> the map will use identity ({@code ==}) comparison
    176    * to determine equality of soft keys, which may not behave as you expect.
    177    * For example, storing a key in the map and then attempting a lookup
    178    * using a different but {@link Object#equals(Object) equals}-equivalent
    179    * key will always fail.
    180    *
    181    * @throws IllegalStateException if the key strength was already set
    182    * @see SoftReference
    183    */
    184   @GwtIncompatible("java.lang.ref.SoftReference")
    185   public MapMaker softKeys() {
    186     return setKeyStrength(Strength.SOFT);
    187   }
    188 
    189   private MapMaker setKeyStrength(Strength strength) {
    190     if (keyStrength != Strength.STRONG) {
    191       throw new IllegalStateException("Key strength was already set to "
    192           + keyStrength + ".");
    193     }
    194     keyStrength = strength;
    195     useCustomMap = true;
    196     return this;
    197   }
    198 
    199   /**
    200    * Specifies that each value (not key) stored in the map should be
    201    * wrapped in a {@link WeakReference} (by default, strong references
    202    * are used).
    203    *
    204    * <p>Weak values will be garbage collected once they are weakly
    205    * reachable. This makes them a poor candidate for caching; consider
    206    * {@link #softValues()} instead.
    207    *
    208    * <p><b>Note:</b> the map will use identity ({@code ==}) comparison
    209    * to determine equality of weak values. This will notably impact
    210    * the behavior of {@link Map#containsValue(Object) containsValue},
    211    * {@link ConcurrentMap#remove(Object, Object) remove(Object, Object)},
    212    * and {@link ConcurrentMap#replace(Object, Object, Object) replace(K, V, V)}.
    213    *
    214    * @throws IllegalStateException if the key strength was already set
    215    * @see WeakReference
    216    */
    217   @GwtIncompatible("java.lang.ref.WeakReference")
    218   public MapMaker weakValues() {
    219     return setValueStrength(Strength.WEAK);
    220   }
    221 
    222   /**
    223    * Specifies that each value (not key) stored in the map should be
    224    * wrapped in a {@link SoftReference} (by default, strong references
    225    * are used).
    226    *
    227    * <p>Soft values will be garbage collected in response to memory
    228    * demand, and in a least-recently-used manner. This makes them a
    229    * good candidate for caching.
    230    *
    231    * <p><b>Note:</b> the map will use identity ({@code ==}) comparison
    232    * to determine equality of soft values. This will notably impact
    233    * the behavior of {@link Map#containsValue(Object) containsValue},
    234    * {@link ConcurrentMap#remove(Object, Object) remove(Object, Object)},
    235    * and {@link ConcurrentMap#replace(Object, Object, Object) replace(K, V, V)}.
    236    *
    237    * @throws IllegalStateException if the value strength was already set
    238    * @see SoftReference
    239    */
    240   @GwtIncompatible("java.lang.ref.SoftReference")
    241   public MapMaker softValues() {
    242     return setValueStrength(Strength.SOFT);
    243   }
    244 
    245   private MapMaker setValueStrength(Strength strength) {
    246     if (valueStrength != Strength.STRONG) {
    247       throw new IllegalStateException("Value strength was already set to "
    248           + valueStrength + ".");
    249     }
    250     valueStrength = strength;
    251     useCustomMap = true;
    252     return this;
    253   }
    254 
    255   /**
    256    * Specifies that each entry should be automatically removed from the
    257    * map once a fixed duration has passed since the entry's creation.
    258    *
    259    * @param duration the length of time after an entry is created that it
    260    *     should be automatically removed
    261    * @param unit the unit that {@code duration} is expressed in
    262    * @throws IllegalArgumentException if {@code duration} is not positive
    263    * @throws IllegalStateException if the expiration time was already set
    264    */
    265   public MapMaker expiration(long duration, TimeUnit unit) {
    266     if (expirationNanos != 0) {
    267       throw new IllegalStateException("expiration time of "
    268           + expirationNanos + " ns was already set");
    269     }
    270     if (duration <= 0) {
    271       throw new IllegalArgumentException("invalid duration: " + duration);
    272     }
    273     this.expirationNanos = unit.toNanos(duration);
    274     useCustomMap = true;
    275     return this;
    276   }
    277 
    278   /**
    279    * Builds the final map, without on-demand computation of values. This method
    280    * does not alter the state of this {@code MapMaker} instance, so it can be
    281    * invoked again to create multiple independent maps.
    282    *
    283    * @param <K> the type of keys to be stored in the returned map
    284    * @param <V> the type of values to be stored in the returned map
    285    * @return a concurrent map having the requested features
    286    */
    287   public <K, V> ConcurrentMap<K, V> makeMap() {
    288     return useCustomMap
    289         ? new StrategyImpl<K, V>(this).map
    290         : new ConcurrentHashMap<K, V>(builder.getInitialCapacity(),
    291             0.75f, builder.getConcurrencyLevel());
    292   }
    293 
    294   /**
    295    * Builds a map that supports atomic, on-demand computation of values. {@link
    296    * Map#get} either returns an already-computed value for the given key,
    297    * atomically computes it using the supplied function, or, if another thread
    298    * is currently computing the value for this key, simply waits for that thread
    299    * to finish and returns its computed value. Note that the function may be
    300    * executed concurrently by multiple threads, but only for distinct keys.
    301    *
    302    * <p>If an entry's value has not finished computing yet, query methods
    303    * besides {@code get} return immediately as if an entry doesn't exist. In
    304    * other words, an entry isn't externally visible until the value's
    305    * computation completes.
    306    *
    307    * <p>{@link Map#get} on the returned map will never return {@code null}. It
    308    * may throw:
    309    *
    310    * <ul>
    311    * <li>{@link NullPointerException} if the key is null or the computing
    312    *     function returns null
    313    * <li>{@link ComputationException} if an exception was thrown by the
    314    *     computing function. If that exception is already of type {@link
    315    *     ComputationException}, it is propagated directly; otherwise it is
    316    *     wrapped.
    317    * </ul>
    318    *
    319    * <p><b>Note:</b> Callers of {@code get} <i>must</i> ensure that the key
    320    * argument is of type {@code K}. The {@code get} method accepts {@code
    321    * Object}, so the key type is not checked at compile time. Passing an object
    322    * of a type other than {@code K} can result in that object being unsafely
    323    * passed to the computing function as type {@code K}, and unsafely stored in
    324    * the map.
    325    *
    326    * <p>If {@link Map#put} is called before a computation completes, other
    327    * threads waiting on the computation will wake up and return the stored
    328    * value. When the computation completes, its new result will overwrite the
    329    * value that was put in the map manually.
    330    *
    331    * <p>This method does not alter the state of this {@code MapMaker} instance,
    332    * so it can be invoked again to create multiple independent maps.
    333    */
    334   public <K, V> ConcurrentMap<K, V> makeComputingMap(
    335       Function<? super K, ? extends V> computingFunction) {
    336     return new StrategyImpl<K, V>(this, computingFunction).map;
    337   }
    338 
    339   // Remainder of this file is private implementation details
    340 
    341   private enum Strength {
    342     WEAK {
    343       @Override boolean equal(Object a, Object b) {
    344         return a == b;
    345       }
    346       @Override int hash(Object o) {
    347         return System.identityHashCode(o);
    348       }
    349       @Override <K, V> ValueReference<K, V> referenceValue(
    350           ReferenceEntry<K, V> entry, V value) {
    351         return new WeakValueReference<K, V>(value, entry);
    352       }
    353       @Override <K, V> ReferenceEntry<K, V> newEntry(
    354           Internals<K, V, ReferenceEntry<K, V>> internals, K key,
    355           int hash, ReferenceEntry<K, V> next) {
    356         return (next == null)
    357             ? new WeakEntry<K, V>(internals, key, hash)
    358             : new LinkedWeakEntry<K, V>(internals, key, hash, next);
    359       }
    360       @Override <K, V> ReferenceEntry<K, V> copyEntry(
    361           K key, ReferenceEntry<K, V> original,
    362           ReferenceEntry<K, V> newNext) {
    363         WeakEntry<K, V> from = (WeakEntry<K, V>) original;
    364         return (newNext == null)
    365             ? new WeakEntry<K, V>(from.internals, key, from.hash)
    366             : new LinkedWeakEntry<K, V>(
    367                 from.internals, key, from.hash, newNext);
    368       }
    369     },
    370 
    371     SOFT {
    372       @Override boolean equal(Object a, Object b) {
    373         return a == b;
    374       }
    375       @Override int hash(Object o) {
    376         return System.identityHashCode(o);
    377       }
    378       @Override <K, V> ValueReference<K, V> referenceValue(
    379           ReferenceEntry<K, V> entry, V value) {
    380         return new SoftValueReference<K, V>(value, entry);
    381       }
    382       @Override <K, V> ReferenceEntry<K, V> newEntry(
    383           Internals<K, V, ReferenceEntry<K, V>> internals, K key,
    384           int hash, ReferenceEntry<K, V> next) {
    385         return (next == null)
    386             ? new SoftEntry<K, V>(internals, key, hash)
    387             : new LinkedSoftEntry<K, V>(internals, key, hash, next);
    388       }
    389       @Override <K, V> ReferenceEntry<K, V> copyEntry(
    390           K key, ReferenceEntry<K, V> original,
    391           ReferenceEntry<K, V> newNext) {
    392         SoftEntry<K, V> from = (SoftEntry<K, V>) original;
    393         return (newNext == null)
    394             ? new SoftEntry<K, V>(from.internals, key, from.hash)
    395             : new LinkedSoftEntry<K, V>(
    396                 from.internals, key, from.hash, newNext);
    397       }
    398     },
    399 
    400     STRONG {
    401       @Override boolean equal(Object a, Object b) {
    402         return a.equals(b);
    403       }
    404       @Override int hash(Object o) {
    405         return o.hashCode();
    406       }
    407       @Override <K, V> ValueReference<K, V> referenceValue(
    408           ReferenceEntry<K, V> entry, V value) {
    409         return new StrongValueReference<K, V>(value);
    410       }
    411       @Override <K, V> ReferenceEntry<K, V> newEntry(
    412           Internals<K, V, ReferenceEntry<K, V>> internals, K key,
    413           int hash, ReferenceEntry<K, V> next) {
    414         return (next == null)
    415             ? new StrongEntry<K, V>(internals, key, hash)
    416             : new LinkedStrongEntry<K, V>(
    417                 internals, key, hash, next);
    418       }
    419       @Override <K, V> ReferenceEntry<K, V> copyEntry(
    420           K key, ReferenceEntry<K, V> original,
    421           ReferenceEntry<K, V> newNext) {
    422         StrongEntry<K, V> from = (StrongEntry<K, V>) original;
    423         return (newNext == null)
    424             ? new StrongEntry<K, V>(from.internals, key, from.hash)
    425             : new LinkedStrongEntry<K, V>(
    426                 from.internals, key, from.hash, newNext);
    427       }
    428     };
    429 
    430     /**
    431      * Determines if two keys or values are equal according to this
    432      * strength strategy.
    433      */
    434     abstract boolean equal(Object a, Object b);
    435 
    436     /**
    437      * Hashes a key according to this strategy.
    438      */
    439     abstract int hash(Object o);
    440 
    441     /**
    442      * Creates a reference for the given value according to this value
    443      * strength.
    444      */
    445     abstract <K, V> ValueReference<K, V> referenceValue(
    446         ReferenceEntry<K, V> entry, V value);
    447 
    448     /**
    449      * Creates a new entry based on the current key strength.
    450      */
    451     abstract <K, V> ReferenceEntry<K, V> newEntry(
    452         Internals<K, V, ReferenceEntry<K, V>> internals, K key,
    453         int hash, ReferenceEntry<K, V> next);
    454 
    455     /**
    456      * Creates a new entry and copies the value and other state from an
    457      * existing entry.
    458      */
    459     abstract <K, V> ReferenceEntry<K, V> copyEntry(K key,
    460         ReferenceEntry<K, V> original, ReferenceEntry<K, V> newNext);
    461   }
    462 
    463   private static class StrategyImpl<K, V> implements Serializable,
    464       ComputingStrategy<K, V, ReferenceEntry<K, V>> {
    465     final Strength keyStrength;
    466     final Strength valueStrength;
    467     final ConcurrentMap<K, V> map;
    468     final long expirationNanos;
    469     Internals<K, V, ReferenceEntry<K, V>> internals;
    470 
    471     StrategyImpl(MapMaker maker) {
    472       this.keyStrength = maker.keyStrength;
    473       this.valueStrength = maker.valueStrength;
    474       this.expirationNanos = maker.expirationNanos;
    475 
    476       map = maker.builder.buildMap(this);
    477     }
    478 
    479     StrategyImpl(
    480         MapMaker maker, Function<? super K, ? extends V> computer) {
    481       this.keyStrength = maker.keyStrength;
    482       this.valueStrength = maker.valueStrength;
    483       this.expirationNanos = maker.expirationNanos;
    484 
    485       map = maker.builder.buildComputingMap(this, computer);
    486     }
    487 
    488     public void setValue(ReferenceEntry<K, V> entry, V value) {
    489       setValueReference(
    490           entry, valueStrength.referenceValue(entry, value));
    491       if (expirationNanos > 0) {
    492         scheduleRemoval(entry.getKey(), value);
    493       }
    494     }
    495 
    496     void scheduleRemoval(K key, V value) {
    497       /*
    498        * TODO: Keep weak reference to map, too. Build a priority
    499        * queue out of the entries themselves instead of creating a
    500        * task per entry. Then, we could have one recurring task per
    501        * map (which would clean the entire map and then reschedule
    502        * itself depending upon when the next expiration comes). We
    503        * also want to avoid removing an entry prematurely if the
    504        * entry was set to the same value again.
    505        */
    506       final WeakReference<K> keyReference = new WeakReference<K>(key);
    507       final WeakReference<V> valueReference = new WeakReference<V>(value);
    508       ExpirationTimer.instance.schedule(
    509           new TimerTask() {
    510             @Override public void run() {
    511               K key = keyReference.get();
    512               if (key != null) {
    513                 // Remove if the value is still the same.
    514                 map.remove(key, valueReference.get());
    515               }
    516             }
    517           }, TimeUnit.NANOSECONDS.toMillis(expirationNanos));
    518     }
    519 
    520     public boolean equalKeys(K a, Object b) {
    521       return keyStrength.equal(a, b);
    522     }
    523 
    524     public boolean equalValues(V a, Object b) {
    525       return valueStrength.equal(a, b);
    526     }
    527 
    528     public int hashKey(Object key) {
    529       return keyStrength.hash(key);
    530     }
    531 
    532     public K getKey(ReferenceEntry<K, V> entry) {
    533       return entry.getKey();
    534     }
    535 
    536     public int getHash(ReferenceEntry<K, V> entry) {
    537       return entry.getHash();
    538     }
    539 
    540     public ReferenceEntry<K, V> newEntry(
    541         K key, int hash, ReferenceEntry<K, V> next) {
    542       return keyStrength.newEntry(internals, key, hash, next);
    543     }
    544 
    545     public ReferenceEntry<K, V> copyEntry(K key,
    546         ReferenceEntry<K, V> original, ReferenceEntry<K, V> newNext) {
    547       ValueReference<K, V> valueReference = original.getValueReference();
    548       if (valueReference == COMPUTING) {
    549         ReferenceEntry<K, V> newEntry
    550             = newEntry(key, original.getHash(), newNext);
    551         newEntry.setValueReference(
    552             new FutureValueReference(original, newEntry));
    553         return newEntry;
    554       } else {
    555         ReferenceEntry<K, V> newEntry
    556             = newEntry(key, original.getHash(), newNext);
    557         newEntry.setValueReference(valueReference.copyFor(newEntry));
    558         return newEntry;
    559       }
    560     }
    561 
    562     /**
    563      * Waits for a computation to complete. Returns the result of the
    564      * computation or null if none was available.
    565      */
    566     public V waitForValue(ReferenceEntry<K, V> entry)
    567         throws InterruptedException {
    568       ValueReference<K, V> valueReference = entry.getValueReference();
    569       if (valueReference == COMPUTING) {
    570         synchronized (entry) {
    571           while ((valueReference = entry.getValueReference())
    572               == COMPUTING) {
    573             entry.wait();
    574           }
    575         }
    576       }
    577       return valueReference.waitForValue();
    578     }
    579 
    580     /**
    581      * Used by CustomConcurrentHashMap to retrieve values. Returns null
    582      * instead of blocking or throwing an exception.
    583      */
    584     public V getValue(ReferenceEntry<K, V> entry) {
    585       ValueReference<K, V> valueReference = entry.getValueReference();
    586       return valueReference.get();
    587     }
    588 
    589     public V compute(K key, final ReferenceEntry<K, V> entry,
    590         Function<? super K, ? extends V> computer) {
    591       V value;
    592       try {
    593         value = computer.apply(key);
    594       } catch (ComputationException e) {
    595         // if computer has thrown a computation exception, propagate rather
    596         // than wrap
    597         setValueReference(entry,
    598             new ComputationExceptionReference<K, V>(e.getCause()));
    599         throw e;
    600       } catch (Throwable t) {
    601         setValueReference(
    602           entry, new ComputationExceptionReference<K, V>(t));
    603         throw new ComputationException(t);
    604       }
    605 
    606       if (value == null) {
    607         String message
    608             = computer + " returned null for key " + key + ".";
    609         setValueReference(
    610             entry, new NullOutputExceptionReference<K, V>(message));
    611         throw new NullOutputException(message);
    612       } else {
    613         setValue(entry, value);
    614       }
    615       return value;
    616     }
    617 
    618     /**
    619      * Sets the value reference on an entry and notifies waiting
    620      * threads.
    621      */
    622     void setValueReference(ReferenceEntry<K, V> entry,
    623         ValueReference<K, V> valueReference) {
    624       boolean notifyOthers = (entry.getValueReference() == COMPUTING);
    625       entry.setValueReference(valueReference);
    626       if (notifyOthers) {
    627         synchronized (entry) {
    628           entry.notifyAll();
    629         }
    630       }
    631     }
    632 
    633     /**
    634      * Points to an old entry where a value is being computed. Used to
    635      * support non-blocking copying of entries during table expansion,
    636      * removals, etc.
    637      */
    638     private class FutureValueReference implements ValueReference<K, V> {
    639       final ReferenceEntry<K, V> original;
    640       final ReferenceEntry<K, V> newEntry;
    641 
    642       FutureValueReference(
    643           ReferenceEntry<K, V> original, ReferenceEntry<K, V> newEntry) {
    644         this.original = original;
    645         this.newEntry = newEntry;
    646       }
    647 
    648       public V get() {
    649         boolean success = false;
    650         try {
    651           V value = original.getValueReference().get();
    652           success = true;
    653           return value;
    654         } finally {
    655           if (!success) {
    656             removeEntry();
    657           }
    658         }
    659       }
    660 
    661       public ValueReference<K, V> copyFor(ReferenceEntry<K, V> entry) {
    662         return new FutureValueReference(original, entry);
    663       }
    664 
    665       public V waitForValue() throws InterruptedException {
    666         boolean success = false;
    667         try {
    668           // assert that key != null
    669           V value = StrategyImpl.this.waitForValue(original);
    670           success = true;
    671           return value;
    672         } finally {
    673           if (!success) {
    674             removeEntry();
    675           }
    676         }
    677       }
    678 
    679       /**
    680        * Removes the entry in the event of an exception. Ideally,
    681        * we'd clean up as soon as the computation completes, but we
    682        * can't do that without keeping a reference to this entry from
    683        * the original.
    684        */
    685       void removeEntry() {
    686         internals.removeEntry(newEntry);
    687       }
    688     }
    689 
    690     public ReferenceEntry<K, V> getNext(
    691         ReferenceEntry<K, V> entry) {
    692       return entry.getNext();
    693     }
    694 
    695     public void setInternals(
    696         Internals<K, V, ReferenceEntry<K, V>> internals) {
    697       this.internals = internals;
    698     }
    699 
    700     private static final long serialVersionUID = 0;
    701 
    702     private void writeObject(ObjectOutputStream out)
    703         throws IOException {
    704       // Custom serialization code ensures that the key and value
    705       // strengths are written before the map. We'll need them to
    706       // deserialize the map entries.
    707       out.writeObject(keyStrength);
    708       out.writeObject(valueStrength);
    709       out.writeLong(expirationNanos);
    710 
    711       // TODO: It is possible for the strategy to try to use the map
    712       // or internals during deserialization, for example, if an
    713       // entry gets reclaimed. We could detect this case and queue up
    714       // removals to be flushed after we deserialize the map.
    715       out.writeObject(internals);
    716       out.writeObject(map);
    717     }
    718 
    719     /**
    720      * Fields used during deserialization. We use a nested class so we
    721      * don't load them until we need them. We need to use reflection to
    722      * set final fields outside of the constructor.
    723      */
    724     private static class Fields {
    725       static final Field keyStrength = findField("keyStrength");
    726       static final Field valueStrength = findField("valueStrength");
    727       static final Field expirationNanos = findField("expirationNanos");
    728       static final Field internals = findField("internals");
    729       static final Field map = findField("map");
    730 
    731       static Field findField(String name) {
    732         try {
    733           Field f = StrategyImpl.class.getDeclaredField(name);
    734           f.setAccessible(true);
    735           return f;
    736         } catch (NoSuchFieldException e) {
    737           throw new AssertionError(e);
    738         }
    739       }
    740     }
    741 
    742     private void readObject(ObjectInputStream in)
    743         throws IOException, ClassNotFoundException {
    744       try {
    745         Fields.keyStrength.set(this, in.readObject());
    746         Fields.valueStrength.set(this, in.readObject());
    747         Fields.expirationNanos.set(this, in.readLong());
    748         Fields.internals.set(this, in.readObject());
    749         Fields.map.set(this, in.readObject());
    750       } catch (IllegalAccessException e) {
    751         throw new AssertionError(e);
    752       }
    753     }
    754   }
    755 
    756   /** A reference to a value. */
    757   private interface ValueReference<K, V> {
    758     /**
    759      * Gets the value. Does not block or throw exceptions.
    760      */
    761     V get();
    762 
    763     /** Creates a copy of this reference for the given entry. */
    764     ValueReference<K, V> copyFor(ReferenceEntry<K, V> entry);
    765 
    766     /**
    767      * Waits for a value that may still be computing. Unlike get(),
    768      * this method can block (in the case of FutureValueReference) or
    769      * throw an exception.
    770      */
    771     V waitForValue() throws InterruptedException;
    772   }
    773 
    774   private static final ValueReference<Object, Object> COMPUTING
    775       = new ValueReference<Object, Object>() {
    776     public Object get() {
    777       return null;
    778     }
    779     public ValueReference<Object, Object> copyFor(
    780         ReferenceEntry<Object, Object> entry) {
    781       throw new AssertionError();
    782     }
    783     public Object waitForValue() {
    784       throw new AssertionError();
    785     }
    786   };
    787 
    788   /**
    789    * Singleton placeholder that indicates a value is being computed.
    790    */
    791   @SuppressWarnings("unchecked")
    792   // Safe because impl never uses a parameter or returns any non-null value
    793   private static <K, V> ValueReference<K, V> computing() {
    794     return (ValueReference<K, V>) COMPUTING;
    795   }
    796 
    797   /** Used to provide null output exceptions to other threads. */
    798   private static class NullOutputExceptionReference<K, V>
    799       implements ValueReference<K, V> {
    800     final String message;
    801     NullOutputExceptionReference(String message) {
    802       this.message = message;
    803     }
    804     public V get() {
    805       return null;
    806     }
    807     public ValueReference<K, V> copyFor(
    808         ReferenceEntry<K, V> entry) {
    809       return this;
    810     }
    811     public V waitForValue() {
    812       throw new NullOutputException(message);
    813     }
    814   }
    815 
    816   /** Used to provide computation exceptions to other threads. */
    817   private static class ComputationExceptionReference<K, V>
    818       implements ValueReference<K, V> {
    819     final Throwable t;
    820     ComputationExceptionReference(Throwable t) {
    821       this.t = t;
    822     }
    823     public V get() {
    824       return null;
    825     }
    826     public ValueReference<K, V> copyFor(
    827         ReferenceEntry<K, V> entry) {
    828       return this;
    829     }
    830     public V waitForValue() {
    831       throw new AsynchronousComputationException(t);
    832     }
    833   }
    834 
    835   /** Wrapper class ensures that queue isn't created until it's used. */
    836   private static class QueueHolder {
    837     static final FinalizableReferenceQueue queue
    838         = new FinalizableReferenceQueue();
    839   }
    840 
    841   /**
    842    * An entry in a reference map.
    843    */
    844   private interface ReferenceEntry<K, V> {
    845     /**
    846      * Gets the value reference from this entry.
    847      */
    848     ValueReference<K, V> getValueReference();
    849 
    850     /**
    851      * Sets the value reference for this entry.
    852      *
    853      * @param valueReference
    854      */
    855     void setValueReference(ValueReference<K, V> valueReference);
    856 
    857     /**
    858      * Removes this entry from the map if its value reference hasn't
    859      * changed.  Used to clean up after values. The value reference can
    860      * just call this method on the entry so it doesn't have to keep
    861      * its own reference to the map.
    862      */
    863     void valueReclaimed();
    864 
    865     /** Gets the next entry in the chain. */
    866     ReferenceEntry<K, V> getNext();
    867 
    868     /** Gets the entry's hash. */
    869     int getHash();
    870 
    871     /** Gets the key for this entry. */
    872     public K getKey();
    873   }
    874 
    875   /**
    876    * Used for strongly-referenced keys.
    877    */
    878   private static class StrongEntry<K, V> implements ReferenceEntry<K, V> {
    879     final K key;
    880 
    881     StrongEntry(Internals<K, V, ReferenceEntry<K, V>> internals, K key,
    882         int hash) {
    883       this.internals = internals;
    884       this.key = key;
    885       this.hash = hash;
    886     }
    887 
    888     public K getKey() {
    889       return this.key;
    890     }
    891 
    892     // The code below is exactly the same for each entry type.
    893 
    894     final Internals<K, V, ReferenceEntry<K, V>> internals;
    895     final int hash;
    896     volatile ValueReference<K, V> valueReference = computing();
    897 
    898     public ValueReference<K, V> getValueReference() {
    899       return valueReference;
    900     }
    901     public void setValueReference(
    902         ValueReference<K, V> valueReference) {
    903       this.valueReference = valueReference;
    904     }
    905     public void valueReclaimed() {
    906       internals.removeEntry(this, null);
    907     }
    908     public ReferenceEntry<K, V> getNext() {
    909       return null;
    910     }
    911     public int getHash() {
    912       return hash;
    913     }
    914   }
    915 
    916   private static class LinkedStrongEntry<K, V> extends StrongEntry<K, V> {
    917 
    918     LinkedStrongEntry(Internals<K, V, ReferenceEntry<K, V>> internals,
    919         K key, int hash, ReferenceEntry<K, V> next) {
    920       super(internals, key, hash);
    921       this.next = next;
    922     }
    923 
    924     final ReferenceEntry<K, V> next;
    925 
    926     @Override public ReferenceEntry<K, V> getNext() {
    927       return next;
    928     }
    929   }
    930 
    931   /**
    932    * Used for softly-referenced keys.
    933    */
    934   private static class SoftEntry<K, V> extends FinalizableSoftReference<K>
    935       implements ReferenceEntry<K, V> {
    936     SoftEntry(Internals<K, V, ReferenceEntry<K, V>> internals, K key,
    937         int hash) {
    938       super(key, QueueHolder.queue);
    939       this.internals = internals;
    940       this.hash = hash;
    941     }
    942 
    943     public K getKey() {
    944       return get();
    945     }
    946 
    947     public void finalizeReferent() {
    948       internals.removeEntry(this);
    949     }
    950 
    951     // The code below is exactly the same for each entry type.
    952 
    953     final Internals<K, V, ReferenceEntry<K, V>> internals;
    954     final int hash;
    955     volatile ValueReference<K, V> valueReference = computing();
    956 
    957     public ValueReference<K, V> getValueReference() {
    958       return valueReference;
    959     }
    960     public void setValueReference(
    961         ValueReference<K, V> valueReference) {
    962       this.valueReference = valueReference;
    963     }
    964     public void valueReclaimed() {
    965       internals.removeEntry(this, null);
    966     }
    967     public ReferenceEntry<K, V> getNext() {
    968       return null;
    969     }
    970     public int getHash() {
    971       return hash;
    972     }
    973   }
    974 
    975   private static class LinkedSoftEntry<K, V> extends SoftEntry<K, V> {
    976     LinkedSoftEntry(Internals<K, V, ReferenceEntry<K, V>> internals,
    977         K key, int hash, ReferenceEntry<K, V> next) {
    978       super(internals, key, hash);
    979       this.next = next;
    980     }
    981 
    982     final ReferenceEntry<K, V> next;
    983 
    984     @Override public ReferenceEntry<K, V> getNext() {
    985       return next;
    986     }
    987   }
    988 
    989   /**
    990    * Used for weakly-referenced keys.
    991    */
    992   private static class WeakEntry<K, V> extends FinalizableWeakReference<K>
    993       implements ReferenceEntry<K, V> {
    994     WeakEntry(Internals<K, V, ReferenceEntry<K, V>> internals, K key,
    995         int hash) {
    996       super(key, QueueHolder.queue);
    997       this.internals = internals;
    998       this.hash = hash;
    999     }
   1000 
   1001     public K getKey() {
   1002       return get();
   1003     }
   1004 
   1005     public void finalizeReferent() {
   1006       internals.removeEntry(this);
   1007     }
   1008 
   1009     // The code below is exactly the same for each entry type.
   1010 
   1011     final Internals<K, V, ReferenceEntry<K, V>> internals;
   1012     final int hash;
   1013     volatile ValueReference<K, V> valueReference = computing();
   1014 
   1015     public ValueReference<K, V> getValueReference() {
   1016       return valueReference;
   1017     }
   1018     public void setValueReference(
   1019         ValueReference<K, V> valueReference) {
   1020       this.valueReference = valueReference;
   1021     }
   1022     public void valueReclaimed() {
   1023       internals.removeEntry(this, null);
   1024     }
   1025     public ReferenceEntry<K, V> getNext() {
   1026       return null;
   1027     }
   1028     public int getHash() {
   1029       return hash;
   1030     }
   1031   }
   1032 
   1033   private static class LinkedWeakEntry<K, V> extends WeakEntry<K, V> {
   1034     LinkedWeakEntry(Internals<K, V, ReferenceEntry<K, V>> internals,
   1035         K key, int hash, ReferenceEntry<K, V> next) {
   1036       super(internals, key, hash);
   1037       this.next = next;
   1038     }
   1039 
   1040     final ReferenceEntry<K, V> next;
   1041 
   1042     @Override public ReferenceEntry<K, V> getNext() {
   1043       return next;
   1044     }
   1045   }
   1046 
   1047   /** References a weak value. */
   1048   private static class WeakValueReference<K, V>
   1049       extends FinalizableWeakReference<V>
   1050       implements ValueReference<K, V> {
   1051     final ReferenceEntry<K, V> entry;
   1052 
   1053     WeakValueReference(V referent, ReferenceEntry<K, V> entry) {
   1054       super(referent, QueueHolder.queue);
   1055       this.entry = entry;
   1056     }
   1057 
   1058     public void finalizeReferent() {
   1059       entry.valueReclaimed();
   1060     }
   1061 
   1062     public ValueReference<K, V> copyFor(
   1063         ReferenceEntry<K, V> entry) {
   1064       return new WeakValueReference<K, V>(get(), entry);
   1065     }
   1066 
   1067     public V waitForValue() {
   1068       return get();
   1069     }
   1070   }
   1071 
   1072   /** References a soft value. */
   1073   private static class SoftValueReference<K, V>
   1074       extends FinalizableSoftReference<V>
   1075       implements ValueReference<K, V> {
   1076     final ReferenceEntry<K, V> entry;
   1077 
   1078     SoftValueReference(V referent, ReferenceEntry<K, V> entry) {
   1079       super(referent, QueueHolder.queue);
   1080       this.entry = entry;
   1081     }
   1082 
   1083     public void finalizeReferent() {
   1084       entry.valueReclaimed();
   1085     }
   1086 
   1087     public ValueReference<K, V> copyFor(
   1088         ReferenceEntry<K, V> entry) {
   1089       return new SoftValueReference<K, V>(get(), entry);
   1090     }
   1091 
   1092     public V waitForValue() {
   1093       return get();
   1094     }
   1095   }
   1096 
   1097   /** References a strong value. */
   1098   private static class StrongValueReference<K, V>
   1099       implements ValueReference<K, V> {
   1100     final V referent;
   1101 
   1102     StrongValueReference(V referent) {
   1103       this.referent = referent;
   1104     }
   1105 
   1106     public V get() {
   1107       return referent;
   1108     }
   1109 
   1110     public ValueReference<K, V> copyFor(
   1111         ReferenceEntry<K, V> entry) {
   1112       return this;
   1113     }
   1114 
   1115     public V waitForValue() {
   1116       return get();
   1117     }
   1118   }
   1119 }
   1120