• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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