1 | /* |
2 | * Copyright 2004-2014 H2 Group. Multiple-Licensed under the MPL 2.0, |
3 | * and the EPL 1.0 (http://h2database.com/html/license.html). |
4 | * Initial Developer: H2 Group |
5 | */ |
6 | package org.h2.util; |
7 | |
8 | import java.lang.ref.Reference; |
9 | import java.lang.ref.ReferenceQueue; |
10 | import java.lang.ref.SoftReference; |
11 | import java.util.AbstractMap; |
12 | import java.util.Map; |
13 | import java.util.Set; |
14 | |
15 | /** |
16 | * Map which stores items using SoftReference. Items can be garbage collected |
17 | * and removed. It is not a general purpose cache, as it doesn't implement some |
18 | * methods, and others not according to the map definition, to improve speed. |
19 | * |
20 | * @param <K> the key type |
21 | * @param <V> the value type |
22 | */ |
23 | public class SoftHashMap<K, V> extends AbstractMap<K, V> { |
24 | |
25 | private final Map<K, SoftValue<V>> map; |
26 | private final ReferenceQueue<V> queue = new ReferenceQueue<V>(); |
27 | |
28 | public SoftHashMap() { |
29 | map = New.hashMap(); |
30 | } |
31 | |
32 | @SuppressWarnings("unchecked") |
33 | private void processQueue() { |
34 | while (true) { |
35 | Reference<? extends V> o = queue.poll(); |
36 | if (o == null) { |
37 | return; |
38 | } |
39 | SoftValue<V> k = (SoftValue<V>) o; |
40 | Object key = k.key; |
41 | map.remove(key); |
42 | } |
43 | } |
44 | |
45 | @Override |
46 | public V get(Object key) { |
47 | processQueue(); |
48 | SoftReference<V> o = map.get(key); |
49 | if (o == null) { |
50 | return null; |
51 | } |
52 | return o.get(); |
53 | } |
54 | |
55 | /** |
56 | * Store the object. The return value of this method is null or a |
57 | * SoftReference. |
58 | * |
59 | * @param key the key |
60 | * @param value the value |
61 | * @return null or the old object. |
62 | */ |
63 | @Override |
64 | public V put(K key, V value) { |
65 | processQueue(); |
66 | SoftValue<V> old = map.put(key, new SoftValue<V>(value, queue, key)); |
67 | return old == null ? null : old.get(); |
68 | } |
69 | |
70 | /** |
71 | * Remove an object. |
72 | * |
73 | * @param key the key |
74 | * @return null or the old object |
75 | */ |
76 | @Override |
77 | public V remove(Object key) { |
78 | processQueue(); |
79 | SoftReference<V> ref = map.remove(key); |
80 | return ref == null ? null : ref.get(); |
81 | } |
82 | |
83 | @Override |
84 | public void clear() { |
85 | processQueue(); |
86 | map.clear(); |
87 | } |
88 | |
89 | @Override |
90 | public Set<Entry<K, V>> entrySet() { |
91 | throw new UnsupportedOperationException(); |
92 | } |
93 | |
94 | /** |
95 | * A soft reference that has a hard reference to the key. |
96 | */ |
97 | private static class SoftValue<T> extends SoftReference<T> { |
98 | final Object key; |
99 | |
100 | public SoftValue(T ref, ReferenceQueue<T> q, Object key) { |
101 | super(ref, q); |
102 | this.key = key; |
103 | } |
104 | |
105 | } |
106 | |
107 | } |