1 /* GENERATED SOURCE. DO NOT MODIFY. */ 2 // © 2016 and later: Unicode, Inc. and others. 3 // License & terms of use: http://www.unicode.org/copyright.html#License 4 /* 5 ******************************************************************************* 6 * Copyright (C) 2010-2016, International Business Machines 7 * Corporation and others. All Rights Reserved. 8 ******************************************************************************* 9 */ 10 package ohos.global.icu.impl; 11 12 import java.util.concurrent.ConcurrentHashMap; 13 14 /** 15 * Generic, thread-safe cache implementation, usually storing cached instances 16 * in {@link java.lang.ref.Reference}s via {@link CacheValue}s. 17 * To use, instantiate a subclass which implements the createInstance() method, 18 * and call get() with the key and the data. The get() call will use the data 19 * only if it needs to call createInstance(), otherwise the data is ignored. 20 * 21 * <p>When caching instances while the CacheValue "strength" is {@code SOFT}, 22 * the Java runtime can later release these instances once they are not used any more at all. 23 * If such an instance is then requested again, 24 * the getInstance() method will call createInstance() again and reset the CacheValue. 25 * The cache holds on to its map of keys to CacheValues forever. 26 * 27 * <p>A value can be null if createInstance() returns null. 28 * In this case, it must do so consistently for the same key and data. 29 * 30 * @param <K> Cache lookup key type 31 * @param <V> Cache instance value type (must not be a CacheValue) 32 * @param <D> Data type for creating a new instance value 33 * 34 * @author Markus Scherer, Mark Davis 35 * @hide exposed on OHOS 36 */ 37 public abstract class SoftCache<K, V, D> extends CacheBase<K, V, D> { 38 private ConcurrentHashMap<K, Object> map = new ConcurrentHashMap<K, Object>(); 39 40 @SuppressWarnings("unchecked") 41 @Override getInstance(K key, D data)42 public final V getInstance(K key, D data) { 43 // We synchronize twice, once in the ConcurrentHashMap and 44 // once in valueRef.resetIfCleared(value), 45 // because we prefer the fine-granularity locking of the ConcurrentHashMap 46 // over coarser locking on the whole cache instance. 47 // We use a CacheValue (a second level of indirection) because 48 // ConcurrentHashMap.putIfAbsent() never replaces the key's value, and if it were 49 // a simple Reference we would not be able to reset its value after it has been cleared. 50 // (And ConcurrentHashMap.put() always replaces the value, which we don't want either.) 51 Object mapValue = map.get(key); 52 if(mapValue != null) { 53 if(!(mapValue instanceof CacheValue)) { 54 // The value was stored directly. 55 return (V)mapValue; 56 } 57 CacheValue<V> cv = (CacheValue<V>)mapValue; 58 if(cv.isNull()) { 59 return null; 60 } 61 V value = cv.get(); 62 if(value != null) { 63 return value; 64 } 65 // The instance has been evicted, its Reference cleared. 66 // Create and set a new instance. 67 value = createInstance(key, data); 68 return cv.resetIfCleared(value); 69 } else /* valueRef == null */ { 70 // We had never cached an instance for this key. 71 V value = createInstance(key, data); 72 mapValue = (value != null && CacheValue.futureInstancesWillBeStrong()) ? 73 value : CacheValue.getInstance(value); 74 mapValue = map.putIfAbsent(key, mapValue); 75 if(mapValue == null) { 76 // Normal "put": Our new value is now cached. 77 return value; 78 } 79 // Race condition: Another thread beat us to putting a CacheValue 80 // into the map. Return its value, but just in case the garbage collector 81 // was aggressive, we also offer our new instance for caching. 82 if(!(mapValue instanceof CacheValue)) { 83 // The value was stored directly. 84 return (V)mapValue; 85 } 86 CacheValue<V> cv = (CacheValue<V>)mapValue; 87 return cv.resetIfCleared(value); 88 } 89 } 90 } 91