Reputation: 167
Here's the stub:
public static void testTTLCache() throws Exception {
TTLCache cache = null; /* replace with new YourClass() */
cache.put("key1", "value1", 5);
cache.put("key2", "value2", 10);
System.out.println(cache.get("key1")); // should print value1
System.out.println(cache.get("key2")); // should print value2
Thread.sleep(1000*6);
System.out.println(cache.get("key1")); // should print NULL
System.out.println(cache.get("key2")); // should print value2
Thread.sleep(1000*6);
System.out.println(cache.get("key1")); // should print NULL
System.out.println(cache.get("key2")); // should print NULL
}
Here is its interface on the basis of my requirement, offcourse you can add other method if you need any
public interface TTLCache {
/**
* @param key - The key to associate with the cache
* @param value - The actual value to store in the cache
* @param timeToLiveSeconds - The time to live for this object in the cache
*/
public void put(String key, Object value, long timeToLiveSeconds);
/**
* Returns the Object in the cache that is associated with passed key, or NULL if
* no value is associated with the key
* @param key - The key associated with the value to retrieve
*
*/
public Object get(String key);
}
Upvotes: 2
Views: 8629
Reputation: 8021
Instead of using HashMap for caching mechanism always use WeakHashMap.
Upvotes: 0
Reputation: 167
BTW I solve the problem. In case anyone needs it, here it is:
import java.util.HashMap;
public class TTL implements TTLCache {
private HashMap<String, Object[]> cache = new HashMap<String, Object[]>();
public void put(String key, Object val, long timeToLive) {
timeToLive = System.currentTimeMillis() + timeToLive * 1000;
if(key == null) throw new RuntimeException("Key cannot be null!");
cache.put(key, new Object[]{timeToLive, val});
}
public Object get(String key) {
if (cache.containsKey(key)) {
Long expires = (Long) cache.get(key)[0];
if (expires - System.currentTimeMillis() > 0) {
return cache.get(key)[1];
} else {
remove(key);
}
}
return null;
}
public boolean remove(Object key) {
return removeAndGet(key) != null;
}
public Object removeAndGet(Object key){
Object entry = cache.remove(key);
//System.out.println("entry=" + entry);
if (entry != null) {
return entry;
}
return null;
}
}
Upvotes: 3
Reputation: 200206
A simple, but working, way to do this is to have a ScheduledExecutorService
and on each put
you schedule a removing task with the needed delay:
scheduler.schedule(new Runnable() { public void run() {
cache.remove(key);
}}, timeOut, TimeUnit.SECONDS);
Note that either the map which backs the cache must be thread-safe, or you must add explicit synchronization.
You must be careful to cancel those tasks if a key is reinserted. You must keep a separate map key->Future
, which allow you to cancel the task.
Upvotes: 2
Reputation: 133609
First of all you must distinguish between removing an item from the cache after expiration time and really destroying it.
In Java you don't have control on when an object is effectively destroyed but you just can make objects eligible for destruction and deallocation (by removing any references to them in your code). So if by destroying you mean avoiding to return the value if it's expired then you are ok, if by destroying you mean deallocating it then you are out of luck since the only thing you can do is to remove all references and wait for the garbage collector to do its work.
I see two possible solutions for a TTLCache
implementation:
For example:
void get(String key) {
if (key is expired) {
remove key,value from cache;
return null;
}
else
return value for key;
}
Upvotes: 3