super global user
super global user

Reputation: 167

Destroy the object in java after certain time

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

Answers (4)

Sambit
Sambit

Reputation: 8021

Instead of using HashMap for caching mechanism always use WeakHashMap.

Upvotes: 0

super global user
super global user

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

Marko Topolnik
Marko Topolnik

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

Jack
Jack

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:

  • keep a running thread which manages the expiration of the objects, when you add a new object save its timestamp and its duration, every thread tick check if there are expired objects and remove them from the cahce
  • a lazier approach: don't use a thread, check if an object is still valid only when you try to get it.

For example:

void get(String key) {
  if (key is expired) {
    remove key,value from cache;
    return null;
  }
  else
    return value for key;
}

Upvotes: 3

Related Questions