Last active
October 8, 2019 19:56
-
-
Save ulisseslima/71d25cf73954b630fcbc474df2ff251d to your computer and use it in GitHub Desktop.
TtlMap - Time-to-live Map
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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