• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // © 2016 and later: Unicode, Inc. and others.
2 // License & terms of use: http://www.unicode.org/copyright.html
3 /*
4  *******************************************************************************
5  * Copyright (C) 2009-2010, 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 
LocaleObjectCache()19     public LocaleObjectCache() {
20         this(16, 0.75f, 16);
21     }
22 
LocaleObjectCache(int initialCapacity, float loadFactor, int concurrencyLevel)23     public LocaleObjectCache(int initialCapacity, float loadFactor, int concurrencyLevel) {
24         _map = new ConcurrentHashMap<K, CacheEntry<K, V>>(initialCapacity, loadFactor, concurrencyLevel);
25     }
26 
get(K key)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")
cleanStaleEntries()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 
createObject(K key)67     protected abstract V createObject(K key);
68 
normalizeKey(K key)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 
CacheEntry(K key, V value, ReferenceQueue<V> queue)76         CacheEntry(K key, V value, ReferenceQueue<V> queue) {
77             super(value, queue);
78             _key = key;
79         }
80 
getKey()81         K getKey() {
82             return _key;
83         }
84     }
85 }
86