Example #1
0
        /// <inheritdoc/>
        public override TValue GetOrCreate(TKey key, Func <TKey, TValue> valueFactory)
        {
            object mapValue = map.GetOrAdd(key, (k) =>
            {
                // We had never cached an instance for this key.

                if (valueFactory is null)
                {
                    return(CacheValue <TValue> .GetInstance(null));
                }

                return(valueFactory(k) ?? (object)CacheValue <TValue> .GetInstance(null));
            });

            if (!(mapValue is CacheValue <TValue> cv))
            {
                // The value was stored directly.
                return((TValue)mapValue);
            }
            if (cv.IsNull)
            {
                return(null);
            }
            return(cv.Get());
        }
Example #2
0
        public override V GetInstance(K key, D data)
        {
            // We synchronize twice, once in the ConcurrentHashMap and
            // once in valueRef.resetIfCleared(value),
            // because we prefer the fine-granularity locking of the ConcurrentHashMap
            // over coarser locking on the whole cache instance.
            // We use a CacheValue (a second level of indirection) because
            // ConcurrentHashMap.putIfAbsent() never replaces the key's value, and if it were
            // a simple Reference we would not be able to reset its value after it has been cleared.
            // (And ConcurrentHashMap.put() always replaces the value, which we don't want either.)
            object mapValue = null;

            lock (map)
                map.TryGetValue(key, out mapValue);
            if (mapValue != null)
            {
                if (!(mapValue is CacheValue <V>))
                {
                    // The value was stored directly.
                    return((V)mapValue);
                }
                CacheValue <V> cv = (CacheValue <V>)mapValue;
                if (cv.IsNull)
                {
                    return(null);
                }
                V value = cv.Get();
                if (value != null)
                {
                    return(value);
                }
                // The instance has been evicted, its Reference cleared.
                // Create and set a new instance.
                value = CreateInstance(key, data);
                return(cv.ResetIfCleared(value));
            }
            else /* valueRef == null */
            {
                // We had never cached an instance for this key.
                V value = CreateInstance(key, data);
                mapValue = (value != null && CacheValue <V> .FutureInstancesWillBeStrong) ?
                           value : (object)CacheValue <V> .GetInstance(value);

                object temp;
                lock (map)
                {
                    // ICU4N TODO: use PutIfAbsent logic from elsewhere to utilize ConcurrentDictionary...?
                    if (!map.TryGetValue(key, out temp))
                    {
                        // put if absent
                        map[key] = mapValue;
                    }
                    mapValue = temp;
                }
                if (mapValue == null)
                {
                    // Normal "put": Our new value is now cached.
                    return(value);
                }

                // Race condition: Another thread beat us to putting a CacheValue
                // into the map. Return its value, but just in case the garbage collector
                // was aggressive, we also offer our new instance for caching.
                if (!(mapValue is CacheValue <V>))
                {
                    // The value was stored directly.
                    return((V)mapValue);
                }
                CacheValue <V> cv = (CacheValue <V>)mapValue;
                return(cv.ResetIfCleared(value));
            }
        }