-
Notifications
You must be signed in to change notification settings - Fork 8
Expand file tree
/
Copy pathWeakConcurrentHashMap.java
More file actions
171 lines (154 loc) · 3.93 KB
/
Copy pathWeakConcurrentHashMap.java
File metadata and controls
171 lines (154 loc) · 3.93 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
import java.util.Date;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* A Weak Concurrent Hash Map Solution which stores the keys and values only for a specific amount of time, and then expires after that
* time.
*
* <pre>
*
* // Create a Map Object
* long expiryInMillis = 1 * 60 * 1000; // 1 minute
* WeakConcurrentHashMap<String, Object> map = new WeakConcurrentHashMap<String, Object>(expiryInMillis);
*
* // Use it
* map.put("key", valueObject);
* Object valueObject = map.get("key");
*
* // quit using it
* map.quitMap();
* </pre>
*
* And to check if the map is alive
*
* <pre>
* if (map.isAlive()) {
* // Your operations on map
* }
* </pre>
*
* @author Vivekananthan M
*
* @param <K>
* @param <V>
*/
public class WeakConcurrentHashMap<K, V> extends ConcurrentHashMap<K, V> {
private static final long serialVersionUID = 1L;
private Map<K, Long> timeMap = new ConcurrentHashMap<K, Long>();
private WeakConcurrentHashMapListener<K, V> listener;
private long expiryInMillis;
private boolean mapAlive = true;
public WeakConcurrentHashMap() {
this.expiryInMillis = 10000;
initialize();
}
public WeakConcurrentHashMap(WeakConcurrentHashMapListener<K, V> listener) {
this.listener = listener;
this.expiryInMillis = 10000;
initialize();
}
public WeakConcurrentHashMap(long expiryInMillis) {
this.expiryInMillis = expiryInMillis;
initialize();
}
public WeakConcurrentHashMap(long expiryInMillis, WeakConcurrentHashMapListener<K, V> listener) {
this.expiryInMillis = expiryInMillis;
this.listener = listener;
initialize();
}
void initialize() {
new CleanerThread().start();
}
public void registerRemovalListener(WeakConcurrentHashMapListener<K, V> listener) {
this.listener = listener;
}
/**
* {@inheritDoc}
*
* @throws IllegalStateException if trying to insert values into map after quiting
*/
@Override
public V put(K key, V value) {
if (!mapAlive) {
throw new IllegalStateException("WeakConcurrent Hashmap is no more alive.. Try creating a new one."); // No I18N
}
Date date = new Date();
timeMap.put(key, date.getTime());
V returnVal = super.put(key, value);
if (listener != null) {
listener.notifyOnAdd(key, value);
}
return returnVal;
}
/**
* {@inheritDoc}
*
* @throws IllegalStateException if trying to insert values into map after quiting
*/
@Override
public void putAll(Map<? extends K, ? extends V> m) {
if (!mapAlive) {
throw new IllegalStateException("WeakConcurrent Hashmap is no more alive.. Try creating a new one."); // No I18N
}
for (K key : m.keySet()) {
put(key, m.get(key));
}
}
/**
* {@inheritDoc}
*
* @throws IllegalStateException if trying to insert values into map after quiting
*/
@Override
public V putIfAbsent(K key, V value) {
if (!mapAlive) {
throw new IllegalStateException("WeakConcurrent Hashmap is no more alive.. Try creating a new one."); // No I18N
}
if (!containsKey(key)) {
return put(key, value);
} else {
return get(key);
}
}
/**
* Should call this method when it's no longer required
*/
public void quitMap() {
mapAlive = false;
}
public boolean isAlive() {
return mapAlive;
}
/**
*
* This thread performs the cleaning operation on the concurrent hashmap once in a specified interval. This wait interval is half of the
* time from the expiry time.
*
*
*/
class CleanerThread extends Thread {
@Override
public void run() {
while (mapAlive) {
cleanMap();
try {
Thread.sleep(expiryInMillis / 2);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private void cleanMap() {
long currentTime = new Date().getTime();
for (K key : timeMap.keySet()) {
if (currentTime > (timeMap.get(key) + expiryInMillis)) {
V value = remove(key);
timeMap.remove(key);
if (listener != null) {
listener.notifyOnRemoval(key, value);
}
}
}
}
}
}