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
|
package org.python.pydev.core.cache;
import java.io.Serializable;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.Map.Entry;
/**
* If the cache is to be used by multiple threads,
* the cache must be wrapped with code to synchronize the methods
* cache = (Map)Collections.synchronizedMap(cache);
*
* (it is actually serializable or not depending on its keys and values)
*/
public class LRUCache<Key, Val> implements Cache<Key, Val>, Serializable{
protected int maxSize;
private static final long serialVersionUID = 1L;
private transient int removeEntries;
private transient int initialMaxSize;
public LRUCache(int maxSize){
this.maxSize = maxSize;
cache = createMap(maxSize);
}
protected LinkedHashMap<Key, Val> createMap(int maxSize) {
return new LinkedHashMap<Key,Val>(maxSize+1, .75F, true) {
// This method is called just after a new entry has been added
public boolean removeEldestEntry(Map.Entry eldest) {
return size() > LRUCache.this.maxSize;
}
};
}
public void stopGrowAsNeeded(){
synchronized(this){
removeEntries--;
if(removeEntries == 0){
maxSize = initialMaxSize;
Iterator<Entry<Key, Val>> iter = cache.entrySet().iterator();
//go to the position of the 'eldest' entries
for (int i = 0; i < cache.size() - maxSize; i++) {
iter.next();
}
//and now remove the eldest entries
while(cache.size() > maxSize && iter.hasNext()){
iter.next();
iter.remove();
}
}
}
}
/**
* Can be used to stop removing oldest entries (this can be useful when doing some 'local' operations that want
* to be faster, having the new max size passed as the new 'value'. Note that other calls to this method will
* be ignored and will not change that limit).
*
* Also, the link between startGrowAsNeeded and stopGrowAsNeeded should be synchronized to avoid that one thread
* raises and another one stopping that raise (so, use this with care).
*/
public void startGrowAsNeeded(int newSize){
if(removeEntries > 0){
throw new RuntimeException("There is alrdeady a new size in action. This class should be synched for this access.");
}
synchronized(this){
removeEntries++;
if(removeEntries == 1){
//start
initialMaxSize = maxSize;
maxSize = newSize;
}
}
}
//Create cache
protected LinkedHashMap<Key,Val> cache;
public Val getObj(Key key) {
return cache.get(key);
}
public void remove(Key key) {
cache.remove(key);
}
public void add(Key key, Val val) {
cache.put(key, val);
}
}
|