1 // 2016 and later: Unicode, Inc. and others. 2 // License & terms of use: http://www.unicode.org/copyright.html#License 3 /* 4 ******************************************************************************* 5 * Copyright (C) 2009-2011, International Business Machines Corporation and * 6 * others. All Rights Reserved. * 7 ******************************************************************************* 8 */ 9 package com.ibm.icu.impl.locale; 10 11 import java.lang.ref.ReferenceQueue; 12 import java.lang.ref.SoftReference; 13 import java.util.concurrent.ConcurrentHashMap; 14 15 public abstract class LocaleObjectCache<K, V> { 16 private ConcurrentHashMap<K, CacheEntry<K, V>> _map; 17 private ReferenceQueue<V> _queue = new ReferenceQueue<V>(); 18 19 public LocaleObjectCache() { 20 this(16, 0.75f, 16); 21 } 22 23 public LocaleObjectCache(int initialCapacity, float loadFactor, int concurrencyLevel) { 24 _map = new ConcurrentHashMap<K, CacheEntry<K, V>>(initialCapacity, loadFactor, concurrencyLevel); 25 } 26 27 public V get(K key) { 28 V value = null; 29 30 cleanStaleEntries(); 31 CacheEntry<K, V> entry = _map.get(key); 32 if (entry != null) { 33 value = entry.get(); 34 } 35 if (value == null) { 36 key = normalizeKey(key); 37 V newVal = createObject(key); 38 if (key == null || newVal == null) { 39 // subclass must return non-null key/value object 40 return null; 41 } 42 43 CacheEntry<K, V> newEntry = new CacheEntry<K, V>(key, newVal, _queue); 44 45 while (value == null) { 46 cleanStaleEntries(); 47 entry = _map.putIfAbsent(key, newEntry); 48 if (entry == null) { 49 value = newVal; 50 break; 51 } else { 52 value = entry.get(); 53 } 54 } 55 } 56 return value; 57 } 58 59 @SuppressWarnings("unchecked") 60 private void cleanStaleEntries() { 61 CacheEntry<K, V> entry; 62 while ((entry = (CacheEntry<K, V>)_queue.poll()) != null) { 63 _map.remove(entry.getKey()); 64 } 65 } 66 67 protected abstract V createObject(K key); 68 69 protected K normalizeKey(K key) { 70 return key; 71 } 72 73 private static class CacheEntry<K, V> extends SoftReference<V> { 74 private K _key; 75 76 CacheEntry(K key, V value, ReferenceQueue<V> queue) { 77 super(value, queue); 78 _key = key; 79 } 80 81 K getKey() { 82 return _key; 83 } 84 } 85 } 86