问题
Hi everyone I want to implement cache map in java in which map entries expire after given time.
I have interface like this, I have to implement these methods, but I am not understand how actually start.
public class CacheMapImpl implements CacheMap<Integer, String> {
@Override
public void setTimeToLive(long timeToLive) {
}
@Override
public long getTimeToLive() {
return 0;
}
@Override
public String put(Integer key, String value) {
return null;
}
@Override
public void clearExpired() {
}
@Override
public void clear() {
}
@Override
public boolean containsKey(Object key) {
return false;
}
@Override
public boolean containsValue(Object value) {
return false;
}
@Override
public String get(Object key) {
return null;
}
@Override
public boolean isEmpty() {
return false;
}
@Override
public String remove(Object key) {
return null;
}
@Override
public int size() {
return 0;
}
}
Please tell me how to implement these methods, how to start write little bit code for me, kindly update my cachemap interface with code.
回答1:
You have to manage an internal map with the same key. User your put method to add the new value to your map and also add a value for your internal times map. You can store a Long as a value, which is the concrete time for that value.
Then, start a new thread in background thatc will check all times for all keys in the internal map and remove those that are 'old' entries from both, internal map and your main map.
Here is the code. As I see your Map implements an interface with some methods provided for clear the expired values, I understand you don't need an automatic way to remove expired values. So, the code should be something like:
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
public class CacheMapImpl implements CacheMap<Integer, String> {
private Map<Integer, Long> timesCache = new HashMap<Integer, Long>();
private Map<Integer, String> values = new HashMap<Integer, String>();
/** Time for the elemens to keep alive in the map in milliseconds. */
long timeToLive = 0;
@Override
public void setTimeToLive(long timeToLive) {
this.timeToLive = timeToLive;
}
@Override
public long getTimeToLive() {
return this.timeToLive;
}
@Override
public String put(Integer key, String value) {
values.put(key, value);
timesCache.put(key, System.currentTimeMillis());
return value;
}
@Override
public void clearExpired() {
// Just remove if timeToLive has been set before...
if (timeToLive > 0) {
List<Integer> keysToClear = new ArrayList<Integer>();
long currentTime = System.currentTimeMillis();
// Check what keys to remove
for (Entry<Integer, Long> e : timesCache.entrySet()) {
if ((currentTime - e.getValue().longValue()) > this.timeToLive) {
keysToClear.add(e.getKey());
}
}
// Remove the expired keys
for (Integer key : keysToClear) {
this.timesCache.remove(key);
this.values.remove(key);
}
}
}
@Override
public void clear() {
this.timesCache.clear();
this.values.clear();
}
@Override
public boolean containsKey(Object key) {
return this.values.containsKey(key);
}
@Override
public boolean containsValue(Object value) {
return this.values.containsValue(value);
}
@Override
public String get(Object key) {
return this.values.get(key);
}
@Override
public boolean isEmpty() {
return this.values.isEmpty();
}
@Override
public String remove(Object key) {
String rto = null;
if (containsKey(key)) {
this.values.remove(key);
this.timesCache.remove(key);
rto = key.toString();
}
return rto;
}
@Override
public int size() {
return this.values.size();
}
}
回答2:
How about this
package map;
import java.util.Map;
import lombok.Getter;
public class TimeOutCacheMap<K, V> {
Long timeout;
@Getter
private static class MapValue<V> {
private Long timeOut;
private V v;
public MapValue(Long timeout, V v) {
this.timeOut = timeout;
this.v = v;
}
}
public TimeOutCacheMap(Long timeoutInMilliSeconds, Class<? extends Map> mapClazz) {
if (timeoutInMilliSeconds > 5000000) {
throw new RuntimeException("Timeout can be upto 5000000");
}
this.timeout = timeoutInMilliSeconds;
try {
map = mapClazz.newInstance();
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private Map<K, MapValue<V>> map;
public V put(K k, V v) {
if (k == null) {
throw new RuntimeException("Invalid key");
}
Long currentTime = System.currentTimeMillis();
Long timeOutValue = currentTime + this.timeout;
MapValue<V> newV = new MapValue<V>(timeOutValue, v);
MapValue<V> oldV = map.put(k, newV);
return ((oldV == null) ? null : oldV.getV());
}
public V get(K k) {
if (k == null) {
throw new RuntimeException("Invalid key");
}
Long currentTime = System.currentTimeMillis();
MapValue<V> mapValue = map.get(k);
if (mapValue!=null && mapValue.getTimeOut() != null && mapValue.getTimeOut() >= currentTime) {
return mapValue.getV();
} else {
map.remove(k);
return null;
}
}
}
来源:https://stackoverflow.com/questions/36564256/how-to-implement-cachemap-with-automatic-expiration-of-entries