Skip to content

Instantly share code, notes, and snippets.

@ulisseslima
Last active October 8, 2019 19:56
Show Gist options
  • Save ulisseslima/71d25cf73954b630fcbc474df2ff251d to your computer and use it in GitHub Desktop.
Save ulisseslima/71d25cf73954b630fcbc474df2ff251d to your computer and use it in GitHub Desktop.
TtlMap - Time-to-live Map
import java.util.HashMap;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
/**
* Time-to-live map.
* <p>
* Items have a specified amount of time to be accessed before they are removed.
* Verification is done on get. Time to live is specified on map creation.
* <p>
* https://stackoverflow.com/questions/20827166/destroy-the-object-in-java-after-certain-time
*
* @since Nov 23, 2016
* @author Ulisses Lima
*/
@SuppressWarnings("unchecked")
public class TtlMap<K, V> {
private Function<Long, Boolean> isAlive = (deathTime) -> deathTime - System.currentTimeMillis() > 0;
private HashMap<K, Object[]> cache = new HashMap<>();
private final long ttl;
/**
* @param ttl time to live (in millis)
* @since 7 de out de 2019
*/
public TtlMap(long ttl) {
this.ttl = ttl;
}
/**
* @param key
* @param val
* @since 7 de out de 2019
* @author Ulisses Lima
*/
public void put(K key, V val) {
long deathTime = System.currentTimeMillis() + ttl;
if (key == null)
throw new RuntimeException("Key cannot be null!");
cache.put(key, new Object[] { val, deathTime });
}
/**
* @param key
* @return value or null
* @since 7 de out de 2019
* @author Ulisses Lima
*/
public V get(K key) {
if (cache.containsKey(key)) {
Long deathTime = (Long) cache.get(key)[1];
if (isAlive.apply(deathTime)) {
return (V) cache.get(key)[0];
} else {
remove(key);
}
}
return null;
}
/**
* @param key
* @return true if removed
* @since 7 de out de 2019
* @author Ulisses Lima
*/
public boolean remove(K key) {
return removeAndGet(key) != null;
}
/**
* @param key
* @return value if exists
* @since 7 de out de 2019
* @author Ulisses Lima
*/
public V removeAndGet(Object key) {
Object[] entry = cache.remove(key);
if (entry != null) {
return (V) entry[0];
}
return null;
}
public static void main(String[] args) throws InterruptedException {
if (args.length < 1)
throw new IllegalArgumentException("first arg must be the ttl");
long ttl = TimeUnit.SECONDS.toMillis(Integer.valueOf(args[0]));
TtlMap<String, String> cache = new TtlMap<String, String>(ttl);
String key1 = "test 1";
String key2 = "test 2";
String val1 = "value1";
String val2 = "value2";
cache.put(key1, val1);
cache.put(key2, val2);
String x = cache.get(key1);
if (val1.equals(x)) {
System.out.println(key1 + ": ok");
} else {
System.out.println(key1 + ": fail");
}
x = cache.get(key2);
if (val2.equals(x)) {
System.out.println(key2 + ": ok");
} else {
System.out.println(key2 + ": fail");
}
Thread.sleep(ttl);
x = cache.get(key1);
if (x == null) {
System.out.println(key1 + ", death: ok");
} else {
System.out.println(key1 + ", death: fail");
}
x = cache.get(key2);
if (x == null) {
System.out.println(key2 + ", death: ok");
} else {
System.out.println(key2 + ", death: fail");
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment