Guest User

Untitled

a guest
Jan 20th, 2017
75
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 7.03 KB | None | 0 0
  1. import java.util.Collection;
  2. import java.util.Map;
  3. import java.util.Map.Entry;
  4. import java.util.Set;
  5. import java.util.WeakHashMap;
  6. import java.util.concurrent.ConcurrentHashMap;
  7. import java.util.concurrent.DelayQueue;
  8. import java.util.concurrent.Delayed;
  9. import java.util.concurrent.TimeUnit;
  10.  
  11. /**
  12. * A thread-safe implementation of a HashMap which entries expires after the specified life time.
  13. * The life-time can be defined on a per-key basis, or using a default one, that is passed to the
  14. * constructor.
  15. *
  16. * @author Pierantonio Cangianiello
  17. * @param <K> the Key type
  18. * @param <V> the Value type
  19. */
  20. public class SelfExpiringHashMap<K, V> implements SelfExpiringMap<K, V> {
  21.  
  22. private final Map<K, V> internalMap;
  23.  
  24. private final Map<K, ExpiringKey<K>> expiringKeys;
  25.  
  26. /**
  27. * Holds the map keys using the given life time for expiration.
  28. */
  29. private final DelayQueue<ExpiringKey> delayQueue = new DelayQueue<ExpiringKey>();
  30.  
  31. /**
  32. * The default max life time in milliseconds.
  33. */
  34. private final long maxLifeTimeMillis;
  35.  
  36. public SelfExpiringHashMap() {
  37. internalMap = new ConcurrentHashMap<K, V>();
  38. expiringKeys = new WeakHashMap<K, ExpiringKey<K>>();
  39. this.maxLifeTimeMillis = Long.MAX_VALUE;
  40. }
  41.  
  42. public SelfExpiringHashMap(long defaultMaxLifeTimeMillis) {
  43. internalMap = new ConcurrentHashMap<K, V>();
  44. expiringKeys = new WeakHashMap<K, ExpiringKey<K>>();
  45. this.maxLifeTimeMillis = defaultMaxLifeTimeMillis;
  46. }
  47.  
  48. public SelfExpiringHashMap(long defaultMaxLifeTimeMillis, int initialCapacity) {
  49. internalMap = new ConcurrentHashMap<K, V>(initialCapacity);
  50. expiringKeys = new WeakHashMap<K, ExpiringKey<K>>(initialCapacity);
  51. this.maxLifeTimeMillis = defaultMaxLifeTimeMillis;
  52. }
  53.  
  54. public SelfExpiringHashMap(long defaultMaxLifeTimeMillis, int initialCapacity, float loadFactor) {
  55. internalMap = new ConcurrentHashMap<K, V>(initialCapacity, loadFactor);
  56. expiringKeys = new WeakHashMap<K, ExpiringKey<K>>(initialCapacity, loadFactor);
  57. this.maxLifeTimeMillis = defaultMaxLifeTimeMillis;
  58. }
  59.  
  60. /**
  61. * {@inheritDoc}
  62. */
  63. @Override
  64. public int size() {
  65. cleanup();
  66. return internalMap.size();
  67. }
  68.  
  69. /**
  70. * {@inheritDoc}
  71. */
  72. @Override
  73. public boolean isEmpty() {
  74. cleanup();
  75. return internalMap.isEmpty();
  76. }
  77.  
  78. /**
  79. * {@inheritDoc}
  80. */
  81. @Override
  82. public boolean containsKey(Object key) {
  83. cleanup();
  84. return internalMap.containsKey((K) key);
  85. }
  86.  
  87. /**
  88. * {@inheritDoc}
  89. */
  90. @Override
  91. public boolean containsValue(Object value) {
  92. cleanup();
  93. return internalMap.containsValue((V) value);
  94. }
  95.  
  96. @Override
  97. public V get(Object key) {
  98. cleanup();
  99. renewKey((K) key);
  100. return internalMap.get((K) key);
  101. }
  102.  
  103. /**
  104. * {@inheritDoc}
  105. */
  106. @Override
  107. public V put(K key, V value) {
  108. return this.put(key, value, maxLifeTimeMillis);
  109. }
  110.  
  111. /**
  112. * {@inheritDoc}
  113. */
  114. @Override
  115. public V put(K key, V value, long lifeTimeMillis) {
  116. cleanup();
  117. ExpiringKey delayedKey = new ExpiringKey(key, lifeTimeMillis);
  118. ExpiringKey oldKey = expiringKeys.put((K) key, delayedKey);
  119. if(oldKey != null) {
  120. expireKey(oldKey);
  121. expiringKeys.put((K) key, delayedKey);
  122. }
  123. delayQueue.offer(delayedKey);
  124. return internalMap.put(key, value);
  125. }
  126.  
  127. /**
  128. * {@inheritDoc}
  129. */
  130. @Override
  131. public V remove(Object key) {
  132. V removedValue = internalMap.remove((K) key);
  133. expireKey(expiringKeys.remove((K) key));
  134. return removedValue;
  135. }
  136.  
  137. /**
  138. * Not supported.
  139. */
  140. @Override
  141. public void putAll(Map<? extends K, ? extends V> m) {
  142. throw new UnsupportedOperationException();
  143. }
  144.  
  145. /**
  146. * {@inheritDoc}
  147. */
  148. @Override
  149. public boolean renewKey(K key) {
  150. ExpiringKey<K> delayedKey = expiringKeys.get((K) key);
  151. if (delayedKey != null) {
  152. delayedKey.renew();
  153. return true;
  154. }
  155. return false;
  156. }
  157.  
  158. private void expireKey(ExpiringKey<K> delayedKey) {
  159. if (delayedKey != null) {
  160. delayedKey.expire();
  161. cleanup();
  162. }
  163. }
  164.  
  165. /**
  166. * {@inheritDoc}
  167. */
  168. @Override
  169. public void clear() {
  170. delayQueue.clear();
  171. expiringKeys.clear();
  172. internalMap.clear();
  173. }
  174.  
  175. /**
  176. * Not supported.
  177. */
  178. @Override
  179. public Set<K> keySet() {
  180. throw new UnsupportedOperationException();
  181. }
  182.  
  183. /**
  184. * Not supported.
  185. */
  186. @Override
  187. public Collection<V> values() {
  188. throw new UnsupportedOperationException();
  189. }
  190.  
  191. /**
  192. * Not supported.
  193. */
  194. @Override
  195. public Set<Entry<K, V>> entrySet() {
  196. throw new UnsupportedOperationException();
  197. }
  198.  
  199. private void cleanup() {
  200. ExpiringKey<K> delayedKey = delayQueue.poll();
  201. while (delayedKey != null) {
  202. internalMap.remove(delayedKey.getKey());
  203. expiringKeys.remove(delayedKey.getKey());
  204. delayedKey = delayQueue.poll();
  205. }
  206. }
  207.  
  208. private class ExpiringKey<K> implements Delayed {
  209.  
  210. private long startTime = System.currentTimeMillis();
  211. private final long maxLifeTimeMillis;
  212. private final K key;
  213.  
  214. public ExpiringKey(K key, long maxLifeTimeMillis) {
  215. this.maxLifeTimeMillis = maxLifeTimeMillis;
  216. this.key = key;
  217. }
  218.  
  219. public K getKey() {
  220. return key;
  221. }
  222.  
  223. /**
  224. * {@inheritDoc}
  225. */
  226. @Override
  227. public boolean equals(Object obj) {
  228. if (obj == null) {
  229. return false;
  230. }
  231. if (getClass() != obj.getClass()) {
  232. return false;
  233. }
  234. final ExpiringKey<K> other = (ExpiringKey<K>) obj;
  235. if (this.key != other.key && (this.key == null || !this.key.equals(other.key))) {
  236. return false;
  237. }
  238. return true;
  239. }
  240.  
  241. /**
  242. * {@inheritDoc}
  243. */
  244. @Override
  245. public int hashCode() {
  246. int hash = 7;
  247. hash = 31 * hash + (this.key != null ? this.key.hashCode() : 0);
  248. return hash;
  249. }
  250.  
  251. /**
  252. * {@inheritDoc}
  253. */
  254. @Override
  255. public long getDelay(TimeUnit unit) {
  256. return unit.convert(getDelayMillis(), TimeUnit.MILLISECONDS);
  257. }
  258.  
  259. private long getDelayMillis() {
  260. return (startTime + maxLifeTimeMillis) - System.currentTimeMillis();
  261. }
  262.  
  263. public void renew() {
  264. startTime = System.currentTimeMillis();
  265. }
  266.  
  267. public void expire() {
  268. startTime = System.currentTimeMillis() - maxLifeTimeMillis - 1;
  269. }
  270.  
  271. /**
  272. * {@inheritDoc}
  273. */
  274. @Override
  275. public int compareTo(Delayed that) {
  276. return Long.compare(this.getDelayMillis(), ((ExpiringKey) that).getDelayMillis());
  277. }
  278. }
  279. }
Add Comment
Please, Sign In to add comment