Java Code Examples for java.util.concurrent.ConcurrentMap#replace()

The following examples show how to use java.util.concurrent.ConcurrentMap#replace() . These examples are extracted from open source projects. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example 1
public synchronized void increment(String name, String hostname, Map<String, Set<String>> tags) {
    ConcurrentMap<CounterMetric, Integer> counters = ConcurrentMetricCounters.get();
    CounterMetric counterMetric = new CounterMetric(tags, name, hostname);
    Integer previousValue = counters.putIfAbsent(counterMetric, 1);
    if (previousValue != null){
        boolean ok = counters.replace(counterMetric, previousValue, previousValue + 1);
        // NOTE:
        // This while loop below should never be called since we are using a lock when flushing and
        // incrementing counters.
        while(!ok) {
            logger.warning("Couldn't increment counter " + name + " with value " + (previousValue + 1) +
                    " previousValue = " + previousValue);
            previousValue = counters.get(counterMetric);
            ok = counters.replace(counterMetric, previousValue, previousValue + 1);
        }
    }
    previousValue = previousValue == null ? 0 : previousValue;
    logger.fine("Counter " + name + " updated from previousValue " + previousValue + " to "
            + (previousValue + 1));
}
 
Example 2
static Semaphore getLock(ConcurrentMap<String, Semaphore> locks2, String key) {
    Semaphore lock = locks2.get(key);
    if (lock == null) {
        Semaphore newLock = new Semaphore(1, true);
        locks2.get(null);
        locks2.put(null, null);
        locks2.remove(null);
        locks2.containsKey(null);
        locks2.containsValue(null);
        locks2.putIfAbsent(null, null);
        locks2.remove(null, null);
        locks2.replace(null, null);
        locks2.replace(null, null, null);
        lock = locks2.putIfAbsent(key, lock);
        // value, being null, will *always* throw NullPointerException
        if (lock == null)
            lock = newLock;
    }
    return lock;
}
 
Example 3
Source Project: hbase   File: SequenceIdAccounting.java    License: Apache License 2.0 5 votes vote down vote up
/**
 * Update the store sequence id, e.g., upon executing in-memory compaction
 */
void updateStore(byte[] encodedRegionName, byte[] familyName, Long sequenceId,
    boolean onlyIfGreater) {
  if (sequenceId == null) {
    return;
  }
  Long highest = this.highestSequenceIds.get(encodedRegionName);
  if (highest == null || sequenceId > highest) {
    this.highestSequenceIds.put(encodedRegionName, sequenceId);
  }
  ImmutableByteArray familyNameWrapper = ImmutableByteArray.wrap(familyName);
  synchronized (this.tieLock) {
    ConcurrentMap<ImmutableByteArray, Long> m = getOrCreateLowestSequenceIds(encodedRegionName);
    boolean replaced = false;
    while (!replaced) {
      Long oldSeqId = m.get(familyNameWrapper);
      if (oldSeqId == null) {
        m.put(familyNameWrapper, sequenceId);
        replaced = true;
      } else if (onlyIfGreater) {
        if (sequenceId > oldSeqId) {
          replaced = m.replace(familyNameWrapper, oldSeqId, sequenceId);
        } else {
          return;
        }
      } else { // replace even if sequence id is not greater than oldSeqId
        m.put(familyNameWrapper, sequenceId);
        return;
      }
    }
  }
}
 
Example 4
Source Project: caffeine   File: ConcurrentHashMapTest.java    License: Apache License 2.0 5 votes vote down vote up
/**
 * replace(x, null, y) throws NPE
 */
public void testReplaceValue2_NullPointerException() {
    ConcurrentMap c = map();
    try {
        c.replace("whatever", null, "A");
        shouldThrow();
    } catch (NullPointerException success) {}
}
 
Example 5
Source Project: ignite   File: MarshallerContextImpl.java    License: Apache License 2.0 5 votes vote down vote up
/**
 * @param item Item.
 */
public void onMappingAccepted(final MarshallerMappingItem item) {
    ConcurrentMap<Integer, MappedName> cache = getCacheFor(item.platformId());

    cache.replace(item.typeId(), new MappedName(item.className(), true));

    closProc.runLocalSafe(new MappingStoreTask(fileStore, item.platformId(), item.typeId(), item.className()));
}
 
Example 6
Source Project: caffeine   File: CacheBuilderGwtTest.java    License: Apache License 2.0 4 votes vote down vote up
public void testMapMethods() {
  Cache<Integer, Integer> cache = CaffeinatedGuava.build(Caffeine.newBuilder());

  ConcurrentMap<Integer, Integer> asMap = cache.asMap();

  cache.put(10, 100);
  cache.put(2, 52);

  asMap.replace(2, 79);
  asMap.replace(3, 60);

  assertEquals(null, cache.getIfPresent(3));
  assertEquals(null, asMap.get(3));

  assertEquals(Integer.valueOf(79), cache.getIfPresent(2));
  assertEquals(Integer.valueOf(79), asMap.get(2));

  asMap.replace(10, 100, 50);
  asMap.replace(2, 52, 99);

  assertEquals(Integer.valueOf(50), cache.getIfPresent(10));
  assertEquals(Integer.valueOf(50), asMap.get(10));
  assertEquals(Integer.valueOf(79), cache.getIfPresent(2));
  assertEquals(Integer.valueOf(79), asMap.get(2));

  asMap.remove(10, 100);
  asMap.remove(2, 79);

  assertEquals(Integer.valueOf(50), cache.getIfPresent(10));
  assertEquals(Integer.valueOf(50), asMap.get(10));
  assertEquals(null, cache.getIfPresent(2));
  assertEquals(null, asMap.get(2));

  asMap.putIfAbsent(2, 20);
  asMap.putIfAbsent(10, 20);

  assertEquals(Integer.valueOf(20), cache.getIfPresent(2));
  assertEquals(Integer.valueOf(20), asMap.get(2));
  assertEquals(Integer.valueOf(50), cache.getIfPresent(10));
  assertEquals(Integer.valueOf(50), asMap.get(10));
}
 
Example 7
@Test(dataProvider = "guardedMap", expectedExceptions = NullPointerException.class)
public void replace_withNullValue(ConcurrentMap<Integer, Integer> map) {
  map.replace(1, null);
}
 
Example 8
/**
 * Look-up the value through the cache. This always evaluates the
 * {@code subKeyFactory} function and optionally evaluates
 * {@code valueFactory} function if there is no entry in the cache for given
 * pair of (key, subKey) or the entry has already been cleared.
 *
 * @param key       possibly null key
 * @param parameter parameter used together with key to create sub-key and
 *                  value (should not be null)
 * @return the cached value (never null)
 * @throws NullPointerException if {@code parameter} passed in or
 *                              {@code sub-key} calculated by
 *                              {@code subKeyFactory} or {@code value}
 *                              calculated by {@code valueFactory} is null.
 */
public V get(K key, P parameter) {
    Objects.requireNonNull(parameter);

    expungeStaleEntries();

    Object cacheKey = CacheKey.valueOf(key, refQueue);

    // lazily install the 2nd level valuesMap for the particular cacheKey
    ConcurrentMap<Object, Supplier<V>> valuesMap = map.get(cacheKey);
    if (valuesMap == null) {
        ConcurrentMap<Object, Supplier<V>> oldValuesMap
            = map.putIfAbsent(cacheKey,
                              valuesMap = new ConcurrentHashMap<>());
        if (oldValuesMap != null) {
            valuesMap = oldValuesMap;
        }
    }

    // create subKey and retrieve the possible Supplier<V> stored by that
    // subKey from valuesMap
    Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
    Supplier<V> supplier = valuesMap.get(subKey);
    Factory factory = null;

    while (true) {
        if (supplier != null) {
            // supplier might be a Factory or a CacheValue<V> instance
            V value = supplier.get();
            if (value != null) {
                return value;
            }
        }
        // else no supplier in cache
        // or a supplier that returned null (could be a cleared CacheValue
        // or a Factory that wasn't successful in installing the CacheValue)

        // lazily construct a Factory
        if (factory == null) {
            factory = new Factory(key, parameter, subKey, valuesMap);
        }

        if (supplier == null) {
            supplier = valuesMap.putIfAbsent(subKey, factory);
            if (supplier == null) {
                // successfully installed Factory
                supplier = factory;
            }
            // else retry with winning supplier
        } else {
            if (valuesMap.replace(subKey, supplier, factory)) {
                // successfully replaced
                // cleared CacheEntry / unsuccessful Factory
                // with our Factory
                supplier = factory;
            } else {
                // retry with current supplier
                supplier = valuesMap.get(subKey);
            }
        }
    }
}
 
Example 9
@Test(dataProvider = "guardedMap", expectedExceptions = NullPointerException.class)
public void replaceConditionally_withNullOldValue(ConcurrentMap<Integer, Integer> map) {
  map.replace(1, null, 3);
}
 
Example 10
/**
 * Look-up the value through the cache. This always evaluates the
 * {@code subKeyFactory} function and optionally evaluates
 * {@code valueFactory} function if there is no entry in the cache for given
 * pair of (key, subKey) or the entry has already been cleared.
 *
 * @param key       possibly null key
 * @param parameter parameter used together with key to create sub-key and
 *                  value (should not be null)
 * @return the cached value (never null)
 * @throws NullPointerException if {@code parameter} passed in or
 *                              {@code sub-key} calculated by
 *                              {@code subKeyFactory} or {@code value}
 *                              calculated by {@code valueFactory} is null.
 */
public V get(K key, P parameter) {
    Objects.requireNonNull(parameter);

    expungeStaleEntries();

    Object cacheKey = CacheKey.valueOf(key, refQueue);

    // lazily install the 2nd level valuesMap for the particular cacheKey
    ConcurrentMap<Object, Supplier<V>> valuesMap = map.get(cacheKey);
    if (valuesMap == null) {
        ConcurrentMap<Object, Supplier<V>> oldValuesMap
            = map.putIfAbsent(cacheKey,
                              valuesMap = new ConcurrentHashMap<>());
        if (oldValuesMap != null) {
            valuesMap = oldValuesMap;
        }
    }

    // create subKey and retrieve the possible Supplier<V> stored by that
    // subKey from valuesMap
    Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
    Supplier<V> supplier = valuesMap.get(subKey);
    Factory factory = null;

    while (true) {
        if (supplier != null) {
            // supplier might be a Factory or a CacheValue<V> instance
            V value = supplier.get();
            if (value != null) {
                return value;
            }
        }
        // else no supplier in cache
        // or a supplier that returned null (could be a cleared CacheValue
        // or a Factory that wasn't successful in installing the CacheValue)

        // lazily construct a Factory
        if (factory == null) {
            factory = new Factory(key, parameter, subKey, valuesMap);
        }

        if (supplier == null) {
            supplier = valuesMap.putIfAbsent(subKey, factory);
            if (supplier == null) {
                // successfully installed Factory
                supplier = factory;
            }
            // else retry with winning supplier
        } else {
            if (valuesMap.replace(subKey, supplier, factory)) {
                // successfully replaced
                // cleared CacheEntry / unsuccessful Factory
                // with our Factory
                supplier = factory;
            } else {
                // retry with current supplier
                supplier = valuesMap.get(subKey);
            }
        }
    }
}
 
Example 11
/**
 * Look-up the value through the cache. This always evaluates the
 * {@code subKeyFactory} function and optionally evaluates
 * {@code valueFactory} function if there is no entry in the cache for given
 * pair of (key, subKey) or the entry has already been cleared.
 *
 * @param key       possibly null key
 * @param parameter parameter used together with key to create sub-key and
 *                  value (should not be null)
 * @return the cached value (never null)
 * @throws NullPointerException if {@code parameter} passed in or
 *                              {@code sub-key} calculated by
 *                              {@code subKeyFactory} or {@code value}
 *                              calculated by {@code valueFactory} is null.
 */
public V get(K key, P parameter) {
    Objects.requireNonNull(parameter);

    expungeStaleEntries();

    Object cacheKey = CacheKey.valueOf(key, refQueue);

    // lazily install the 2nd level valuesMap for the particular cacheKey
    ConcurrentMap<Object, Supplier<V>> valuesMap = map.get(cacheKey);
    if (valuesMap == null) {
        ConcurrentMap<Object, Supplier<V>> oldValuesMap
            = map.putIfAbsent(cacheKey,
                              valuesMap = new ConcurrentHashMap<>());
        if (oldValuesMap != null) {
            valuesMap = oldValuesMap;
        }
    }

    // create subKey and retrieve the possible Supplier<V> stored by that
    // subKey from valuesMap
    Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
    Supplier<V> supplier = valuesMap.get(subKey);
    Factory factory = null;

    while (true) {
        if (supplier != null) {
            // supplier might be a Factory or a CacheValue<V> instance
            V value = supplier.get();
            if (value != null) {
                return value;
            }
        }
        // else no supplier in cache
        // or a supplier that returned null (could be a cleared CacheValue
        // or a Factory that wasn't successful in installing the CacheValue)

        // lazily construct a Factory
        if (factory == null) {
            factory = new Factory(key, parameter, subKey, valuesMap);
        }

        if (supplier == null) {
            supplier = valuesMap.putIfAbsent(subKey, factory);
            if (supplier == null) {
                // successfully installed Factory
                supplier = factory;
            }
            // else retry with winning supplier
        } else {
            if (valuesMap.replace(subKey, supplier, factory)) {
                // successfully replaced
                // cleared CacheEntry / unsuccessful Factory
                // with our Factory
                supplier = factory;
            } else {
                // retry with current supplier
                supplier = valuesMap.get(subKey);
            }
        }
    }
}
 
Example 12
/**
 * Look-up the value through the cache. This always evaluates the
 * {@code subKeyFactory} function and optionally evaluates
 * {@code valueFactory} function if there is no entry in the cache for given
 * pair of (key, subKey) or the entry has already been cleared.
 *
 * @param key       possibly null key
 * @param parameter parameter used together with key to create sub-key and
 *                  value (should not be null)
 * @return the cached value (never null)
 * @throws NullPointerException if {@code parameter} passed in or
 *                              {@code sub-key} calculated by
 *                              {@code subKeyFactory} or {@code value}
 *                              calculated by {@code valueFactory} is null.
 */
public V get(K key, P parameter) {
    Objects.requireNonNull(parameter);

    expungeStaleEntries();

    Object cacheKey = CacheKey.valueOf(key, refQueue);

    // lazily install the 2nd level valuesMap for the particular cacheKey
    ConcurrentMap<Object, Supplier<V>> valuesMap = map.get(cacheKey);
    if (valuesMap == null) {
        ConcurrentMap<Object, Supplier<V>> oldValuesMap
            = map.putIfAbsent(cacheKey,
                              valuesMap = new ConcurrentHashMap<>());
        if (oldValuesMap != null) {
            valuesMap = oldValuesMap;
        }
    }

    // create subKey and retrieve the possible Supplier<V> stored by that
    // subKey from valuesMap
    Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
    Supplier<V> supplier = valuesMap.get(subKey);
    Factory factory = null;

    while (true) {
        if (supplier != null) {
            // supplier might be a Factory or a CacheValue<V> instance
            V value = supplier.get();
            if (value != null) {
                return value;
            }
        }
        // else no supplier in cache
        // or a supplier that returned null (could be a cleared CacheValue
        // or a Factory that wasn't successful in installing the CacheValue)

        // lazily construct a Factory
        if (factory == null) {
            factory = new Factory(key, parameter, subKey, valuesMap);
        }

        if (supplier == null) {
            supplier = valuesMap.putIfAbsent(subKey, factory);
            if (supplier == null) {
                // successfully installed Factory
                supplier = factory;
            }
            // else retry with winning supplier
        } else {
            if (valuesMap.replace(subKey, supplier, factory)) {
                // successfully replaced
                // cleared CacheEntry / unsuccessful Factory
                // with our Factory
                supplier = factory;
            } else {
                // retry with current supplier
                supplier = valuesMap.get(subKey);
            }
        }
    }
}
 
Example 13
Source Project: Java8CN   File: WeakCache.java    License: Apache License 2.0 4 votes vote down vote up
/**
 * Look-up the value through the cache. This always evaluates the
 * {@code subKeyFactory} function and optionally evaluates
 * {@code valueFactory} function if there is no entry in the cache for given
 * pair of (key, subKey) or the entry has already been cleared.
 *
 * @param key       possibly null key
 * @param parameter parameter used together with key to create sub-key and
 *                  value (should not be null)
 * @return the cached value (never null)
 * @throws NullPointerException if {@code parameter} passed in or
 *                              {@code sub-key} calculated by
 *                              {@code subKeyFactory} or {@code value}
 *                              calculated by {@code valueFactory} is null.
 */
public V get(K key, P parameter) {
    Objects.requireNonNull(parameter);

    expungeStaleEntries();

    Object cacheKey = CacheKey.valueOf(key, refQueue);

    // lazily install the 2nd level valuesMap for the particular cacheKey
    ConcurrentMap<Object, Supplier<V>> valuesMap = map.get(cacheKey);
    if (valuesMap == null) {
        ConcurrentMap<Object, Supplier<V>> oldValuesMap
            = map.putIfAbsent(cacheKey,
                              valuesMap = new ConcurrentHashMap<>());
        if (oldValuesMap != null) {
            valuesMap = oldValuesMap;
        }
    }

    // create subKey and retrieve the possible Supplier<V> stored by that
    // subKey from valuesMap
    Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
    Supplier<V> supplier = valuesMap.get(subKey);
    Factory factory = null;

    while (true) {
        if (supplier != null) {
            // supplier might be a Factory or a CacheValue<V> instance
            V value = supplier.get();
            if (value != null) {
                return value;
            }
        }
        // else no supplier in cache
        // or a supplier that returned null (could be a cleared CacheValue
        // or a Factory that wasn't successful in installing the CacheValue)

        // lazily construct a Factory
        if (factory == null) {
            factory = new Factory(key, parameter, subKey, valuesMap);
        }

        if (supplier == null) {
            supplier = valuesMap.putIfAbsent(subKey, factory);
            if (supplier == null) {
                // successfully installed Factory
                supplier = factory;
            }
            // else retry with winning supplier
        } else {
            if (valuesMap.replace(subKey, supplier, factory)) {
                // successfully replaced
                // cleared CacheEntry / unsuccessful Factory
                // with our Factory
                supplier = factory;
            } else {
                // retry with current supplier
                supplier = valuesMap.get(subKey);
            }
        }
    }
}
 
Example 14
@Test(dataProvider = "guardedMap", expectedExceptions = NullPointerException.class)
public void replaceConditionally_withNullKeyAndValues(ConcurrentMap<Integer, Integer> map) {
  map.replace(null, null, null);
}
 
Example 15
/**
 * Look-up the value through the cache. This always evaluates the
 * {@code subKeyFactory} function and optionally evaluates
 * {@code valueFactory} function if there is no entry in the cache for given
 * pair of (key, subKey) or the entry has already been cleared.
 *
 * @param key       possibly null key
 * @param parameter parameter used together with key to create sub-key and
 *                  value (should not be null)
 * @return the cached value (never null)
 * @throws NullPointerException if {@code parameter} passed in or
 *                              {@code sub-key} calculated by
 *                              {@code subKeyFactory} or {@code value}
 *                              calculated by {@code valueFactory} is null.
 */
public V get(K key, P parameter) {
    Objects.requireNonNull(parameter);

    expungeStaleEntries();

    Object cacheKey = CacheKey.valueOf(key, refQueue);

    // lazily install the 2nd level valuesMap for the particular cacheKey
    ConcurrentMap<Object, Supplier<V>> valuesMap = map.get(cacheKey);
    if (valuesMap == null) {
        ConcurrentMap<Object, Supplier<V>> oldValuesMap
            = map.putIfAbsent(cacheKey,
                              valuesMap = new ConcurrentHashMap<>());
        if (oldValuesMap != null) {
            valuesMap = oldValuesMap;
        }
    }

    // create subKey and retrieve the possible Supplier<V> stored by that
    // subKey from valuesMap
    Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
    Supplier<V> supplier = valuesMap.get(subKey);
    Factory factory = null;

    while (true) {
        if (supplier != null) {
            // supplier might be a Factory or a CacheValue<V> instance
            V value = supplier.get();
            if (value != null) {
                return value;
            }
        }
        // else no supplier in cache
        // or a supplier that returned null (could be a cleared CacheValue
        // or a Factory that wasn't successful in installing the CacheValue)

        // lazily construct a Factory
        if (factory == null) {
            factory = new Factory(key, parameter, subKey, valuesMap);
        }

        if (supplier == null) {
            supplier = valuesMap.putIfAbsent(subKey, factory);
            if (supplier == null) {
                // successfully installed Factory
                supplier = factory;
            }
            // else retry with winning supplier
        } else {
            if (valuesMap.replace(subKey, supplier, factory)) {
                // successfully replaced
                // cleared CacheEntry / unsuccessful Factory
                // with our Factory
                supplier = factory;
            } else {
                // retry with current supplier
                supplier = valuesMap.get(subKey);
            }
        }
    }
}
 
Example 16
/**
 * Look-up the value through the cache. This always evaluates the
 * {@code subKeyFactory} function and optionally evaluates
 * {@code valueFactory} function if there is no entry in the cache for given
 * pair of (key, subKey) or the entry has already been cleared.
 *
 * @param key       possibly null key
 * @param parameter parameter used together with key to create sub-key and
 *                  value (should not be null)
 * @return the cached value (never null)
 * @throws NullPointerException if {@code parameter} passed in or
 *                              {@code sub-key} calculated by
 *                              {@code subKeyFactory} or {@code value}
 *                              calculated by {@code valueFactory} is null.
 */
public V get(K key, P parameter) {
    Objects.requireNonNull(parameter);

    expungeStaleEntries();

    Object cacheKey = CacheKey.valueOf(key, refQueue);

    // lazily install the 2nd level valuesMap for the particular cacheKey
    ConcurrentMap<Object, Supplier<V>> valuesMap = map.get(cacheKey);
    if (valuesMap == null) {
        ConcurrentMap<Object, Supplier<V>> oldValuesMap
            = map.putIfAbsent(cacheKey,
                              valuesMap = new ConcurrentHashMap<>());
        if (oldValuesMap != null) {
            valuesMap = oldValuesMap;
        }
    }

    // create subKey and retrieve the possible Supplier<V> stored by that
    // subKey from valuesMap
    Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
    Supplier<V> supplier = valuesMap.get(subKey);
    Factory factory = null;

    while (true) {
        if (supplier != null) {
            // supplier might be a Factory or a CacheValue<V> instance
            V value = supplier.get();
            if (value != null) {
                return value;
            }
        }
        // else no supplier in cache
        // or a supplier that returned null (could be a cleared CacheValue
        // or a Factory that wasn't successful in installing the CacheValue)

        // lazily construct a Factory
        if (factory == null) {
            factory = new Factory(key, parameter, subKey, valuesMap);
        }

        if (supplier == null) {
            supplier = valuesMap.putIfAbsent(subKey, factory);
            if (supplier == null) {
                // successfully installed Factory
                supplier = factory;
            }
            // else retry with winning supplier
        } else {
            if (valuesMap.replace(subKey, supplier, factory)) {
                // successfully replaced
                // cleared CacheEntry / unsuccessful Factory
                // with our Factory
                supplier = factory;
            } else {
                // retry with current supplier
                supplier = valuesMap.get(subKey);
            }
        }
    }
}
 
Example 17
@Test(dataProvider = "guardedMap", expectedExceptions = NullPointerException.class)
public void replaceConditionally_withNullNewValue(ConcurrentMap<Integer, Integer> map) {
  map.replace(1, 2, null);
}
 
Example 18
@Test(dataProvider = "guardedMap", expectedExceptions = NullPointerException.class)
public void replaceConditionally_withNullKeyAndNewValue(ConcurrentMap<Integer, Integer> map) {
  map.replace(null, 2, null);
}
 
Example 19
/**
 * Attempts to compute a mapping for the specified key and its current
 * mapped value (or {@code null} if there is no current mapping). For
 * example, to either create or append a {@code String} msg to a value
 * mapping:
 *
 * <pre> {@code
 * map.compute(key, (k, v) -> (v == null) ? msg : v.concat(msg))}</pre>
 * (Method {@link #merge merge()} is often simpler to use for such purposes.)
 *
 * <p>If the remapping function returns {@code null}, the mapping is removed
 * (or remains absent if initially absent).  If the remapping function itself
 * throws an (unchecked) exception, the exception is rethrown, and the current
 * mapping is left unchanged.
 *
 * <p>The remapping function itself should not modify the passed map during
 * computation.
 *
 * <p><b>Implementation Requirements:</b><br>
 * The default implementation is equivalent to performing the following
 * steps for the {@code map}:
 *
 * <pre> {@code
 * for (;;) {
 *   V oldValue = map.get(key);
 *   V newValue = remappingFunction.apply(key, oldValue);
 *   if (newValue != null) {
 *     if ((oldValue != null)
 *       ? map.replace(key, oldValue, newValue)
 *       : map.putIfAbsent(key, newValue) == null)
 *       return newValue;
 *   } else if (oldValue == null || map.remove(key, oldValue)) {
 *     return null;
 *   }
 * }}</pre>
 * When multiple threads attempt updates, map operations and the
 * remapping function may be called multiple times.
 *
 * <p>This implementation assumes that the ConcurrentMap cannot contain null
 * values and {@code get()} returning null unambiguously means the key is
 * absent. Implementations which support null values <strong>must</strong>
 * override this default implementation.
 *
 * @param <K> the type of keys maintained by the passed map
 * @param <V> the type of mapped values in the passed map
 * @param map the {@code ConcurrentMap} on which to execute the {@code compute}
 * operation.
 * @param key key with which the specified value is to be associated
 * @param remappingFunction the remapping function to compute a value
 * @return the new value associated with the specified key, or null if none
 * @throws NullPointerException if the specified key is null and
 *         the map does not support null keys, or the
 *         remappingFunction is null
 * @throws UnsupportedOperationException if the {@code put} operation
 *         is not supported by the map (optional)
 * @throws ClassCastException if the class of the specified key or value
 *         prevents it from being stored in the map (optional)
 * @throws IllegalArgumentException if some property of the specified key
 *         or value prevents it from being stored in this map (optional)
 * @since 1.8
 */
public static <K, V> V compute(ConcurrentMap<K, V> map, K key,
        BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
    Objects.requireNonNull(map);
    retry: for (;;) {
        V oldValue = map.get(key);
        // if putIfAbsent fails, opportunistically use its return value
        haveOldValue: for (;;) {
            V newValue = remappingFunction.apply(key, oldValue);
            if (newValue != null) {
                if (oldValue != null) {
                    if (map.replace(key, oldValue, newValue))
                        return newValue;
                }
                else if ((oldValue = map.putIfAbsent(key, newValue)) == null)
                    return newValue;
                else continue haveOldValue;
            } else if (oldValue == null || map.remove(key, oldValue)) {
                return null;
            }
            continue retry;
        }
    }
}
 
Example 20
/**
 * Look-up the value through the cache. This always evaluates the
 * {@code subKeyFactory} function and optionally evaluates
 * {@code valueFactory} function if there is no entry in the cache for given
 * pair of (key, subKey) or the entry has already been cleared.
 *
 * @param key       possibly null key
 * @param parameter parameter used together with key to create sub-key and
 *                  value (should not be null)
 * @return the cached value (never null)
 * @throws NullPointerException if {@code parameter} passed in or
 *                              {@code sub-key} calculated by
 *                              {@code subKeyFactory} or {@code value}
 *                              calculated by {@code valueFactory} is null.
 */
public V get(K key, P parameter) {
    Objects.requireNonNull(parameter);

    expungeStaleEntries();

    Object cacheKey = CacheKey.valueOf(key, refQueue);

    // lazily install the 2nd level valuesMap for the particular cacheKey
    ConcurrentMap<Object, Supplier<V>> valuesMap = map.get(cacheKey);
    if (valuesMap == null) {
        ConcurrentMap<Object, Supplier<V>> oldValuesMap
            = map.putIfAbsent(cacheKey,
                              valuesMap = new ConcurrentHashMap<>());
        if (oldValuesMap != null) {
            valuesMap = oldValuesMap;
        }
    }

    // create subKey and retrieve the possible Supplier<V> stored by that
    // subKey from valuesMap
    Object subKey = Objects.requireNonNull(subKeyFactory.apply(key, parameter));
    Supplier<V> supplier = valuesMap.get(subKey);
    Factory factory = null;

    while (true) {
        if (supplier != null) {
            // supplier might be a Factory or a CacheValue<V> instance
            V value = supplier.get();
            if (value != null) {
                return value;
            }
        }
        // else no supplier in cache
        // or a supplier that returned null (could be a cleared CacheValue
        // or a Factory that wasn't successful in installing the CacheValue)

        // lazily construct a Factory
        if (factory == null) {
            factory = new Factory(key, parameter, subKey, valuesMap);
        }

        if (supplier == null) {
            supplier = valuesMap.putIfAbsent(subKey, factory);
            if (supplier == null) {
                // successfully installed Factory
                supplier = factory;
            }
            // else retry with winning supplier
        } else {
            if (valuesMap.replace(subKey, supplier, factory)) {
                // successfully replaced
                // cleared CacheEntry / unsuccessful Factory
                // with our Factory
                supplier = factory;
            } else {
                // retry with current supplier
                supplier = valuesMap.get(subKey);
            }
        }
    }
}