1 16 17 package com.google.inject.util; 18 19 import java.io.IOException ; 20 import java.io.ObjectInputStream ; 21 import java.util.concurrent.ConcurrentHashMap ; 22 import java.util.concurrent.ConcurrentMap ; 23 24 29 abstract class AbstractReferenceCache<K, V> extends ReferenceMap<K, V> { 30 31 private static final long serialVersionUID = 0; 32 33 transient ConcurrentMap <Object , FutureValue<V>> futures = 34 new ConcurrentHashMap <Object , FutureValue<V>>(); 35 36 AbstractReferenceCache(ReferenceType keyReferenceType, 37 ReferenceType valueReferenceType) { 38 super(keyReferenceType, valueReferenceType); 39 } 40 41 V internalCreate(K key) { 42 FutureValue<V> futureValue = new FutureValue<V>(); 43 44 Object keyReference = referenceKey(key); 46 FutureValue<V> previous = 47 futures.putIfAbsent(keyReference, futureValue); 48 if (previous == null) { 49 try { 51 V value = internalGet(key); 53 if (value != null) { 54 futureValue.setValue(value); 55 return value; 56 } 57 58 try { 59 value = create(futureValue, key); 60 if (value == null) { 61 throw new NullPointerException ( 62 "create() returned null for: " + key); 63 } 64 futureValue.setValue(value); 65 } catch (Throwable t) { 66 futureValue.setThrowable(t); 67 rethrow(t); 68 } 69 70 putStrategy().execute( 71 this, keyReference, referenceValue(keyReference, value)); 72 73 return value; 74 } finally { 75 futures.remove(keyReference); 76 } 77 } else { 78 if (previous.winningThread() == Thread.currentThread()) { 79 throw new RuntimeException ("Circular reference: " + key); 80 } 81 82 return previous.get(); 84 } 85 } 86 87 private static void rethrow(Throwable t) { 88 if (t instanceof RuntimeException ) { 89 throw (RuntimeException ) t; 90 } 91 if (t instanceof Error ) { 92 throw (Error ) t; 93 } 94 throw new RuntimeException (t); 95 } 96 97 100 abstract V create(FutureValue<V> futureValue, K key); 101 102 113 @SuppressWarnings ("unchecked") 114 @Override public V get(final Object key) { 115 V value = super.get(key); 116 return (value == null) 117 ? internalCreate((K) key) 118 : value; 119 } 120 121 private void readObject(ObjectInputStream in) throws IOException , 122 ClassNotFoundException { 123 in.defaultReadObject(); 124 this.futures = new ConcurrentHashMap <Object , FutureValue<V>>(); 125 } 126 127 130 static class FutureValue<V> { 131 132 133 private boolean set = false; 134 135 136 private V value; 137 138 139 private Throwable t; 140 141 private final Thread winningThread = Thread.currentThread(); 142 143 Thread winningThread() { 144 return winningThread; 145 } 146 147 V get() { 148 if (!set) { 149 boolean interrupted = waitUntilSet(); 150 151 if (interrupted) { 152 Thread.currentThread().interrupt(); 153 } 154 } 155 156 if (t != null) { 157 rethrow(t); 158 } 159 return value; 160 } 161 162 167 private synchronized boolean waitUntilSet() { 168 boolean interrupted = false; 169 while (!set) { 170 try { 171 wait(); 172 } catch (InterruptedException e) { 173 interrupted = true; 174 } 175 } 176 return interrupted; 177 } 178 179 synchronized void setValue(V v) { 180 set(); 181 value = v; 182 } 183 184 synchronized void setThrowable(Throwable t) { 185 set(); 186 this.t = t; 187 } 188 189 private void set() { 190 if (set) { 191 throw new IllegalStateException ("Value is already set."); 192 } 193 set = true; 194 notifyAll(); 195 } 196 } 197 } 198 | Popular Tags |