Caffeine:为每个元素动态设置过期时间
Caffeine 是一个开源的 Java 缓存库,它提供了一个高效且易于使用的缓存解决方案,可以帮助 Java 开发人员快速实现缓存功能,提升应用程序的性能和响应速度。Caffeine 支持多种缓存策略,并具有高性能、低延迟和低内存占用的特点,是 Java 开发人员在构建高性能应用程序时不可或缺的工具之一。
对于Caffeine的缓存过期设置来说,我们知道有
-
expireAfterWrite
:基于创建时间进行过期处理 -
expireAfterAccess
:基于最后访问时间进行过期处理 -
expireAfter
:基于个性化定制的逻辑来实现过期处理(可以定制基于新增、读取、更新等场景的过期策略,甚至支持为不同记录指定不同过期时间)
在Caffeine缓存创建时,可以使用expireAfterWrite
或expireAfterAccess
来设置缓存元素的过期时间,但这种过期时间的设置是基于整个缓存的所有元素来说的,即每个元素的过期时间都是这个指定的时间。
那么如果我们想针对缓存中的每个元素单独设置缓存过期时间要怎么做呢?就要涉及到expireAfter
这个设置。
expireAfter
方法接收一个Expiry
对象来计算缓存项何时过期。在Expiry
对象中需要实现expireAfterCreate
、expireAfterUpdate
、expireAfterRead
三个方法。
- expireAfterCreate: 指定一旦条目创建后的持续时间过了,就应该自动从缓存中删除该条目。为了表示没有过期,可以给一个条目一个过长的周期,比如Long.MAX_VALUE。
- expireAfterUpdate: 指定在更新其值后的持续时间一过,就应自动从缓存中删除该条目。为了表示没有过期,可以给一个条目一个过长的周期,比如Long.MAX_VALUE。可以返回currentDuration来不修改过期时间。
- expireAfterRead: 指定超过最后一次读取后的持续时间,就应自动从缓存中删除该条目。为了表示没有过期,可以给条目一个过长的周期,比如Long.MAX_VALUE。可以返回currentDuration来不修改过期时间。
话不多说,给出代码示例,大家就知道如何来写了
Example
Employee.java
public class Employee {
private int id;
private String firstName;
private String lastName;
private long expiryTime;
public Employee(int id, String firstName, String lastName, long expiryTime) {
super();
this.id = id;
this.firstName = firstName;
this.lastName = lastName;
this.expiryTime = expiryTime;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public long getExpiryTime() {
return expiryTime;
}
public void setExpiryTime(long expiryTime) {
this.expiryTime = expiryTime;
}
@Override
public String toString() {
return "Employee [id=" + id + ", firstName=" + firstName + ", lastName=" + lastName + ", expiryTime="
+ expiryTime + "]";
}
}
CaffeineTest.java
public class CaffeineTest {
private static void printCache(Cache cache) {
System.out.println("Elements in the cache are");
Map map = cache.asMap();
for (Object key : map.keySet()) {
System.out.println(map.get(key));
}
}
public static void main(String args[]) throws InterruptedException {
Cache<Integer, Employee> cache = Caffeine.newBuilder().expireAfter(new Expiry<Integer, Employee>() {
@Override
public long expireAfterCreate(Integer key, Employee emp, long currentTime) {
return TimeUnit.SECONDS.toNanos(emp.getExpiryTime());
}
@Override
public long expireAfterUpdate(Integer key, Employee emp, long currentTime, long currentDuration) {
return currentDuration;
}
@Override
public long expireAfterRead(Integer key, Employee emp, long currentTime, long currentDuration) {
return currentDuration;
}
}).build();
Employee emp1 = new Employee(1, "Krishna", "Gurram", 5l);
Employee emp2 = new Employee(2, "Gopi", "Battu", 8l);
Employee emp3 = new Employee(3, "Saurav", "Sarkar", 15l);
cache.put(emp1.getId(), emp1);
cache.put(emp2.getId(), emp2);
cache.put(emp3.getId(), emp3);
printCache(cache);
System.out.println("\nAbout to sleep for 6 seconds");
TimeUnit.SECONDS.sleep(6);
printCache(cache);
System.out.println("\nAbout to sleep for 10 seconds");
TimeUnit.SECONDS.sleep(4);
/*
* Since cache eviction is done asynchronously, let's execute pending
* maintenance operations needed by the cache
*/
// System.out.println("\nPerforming cleanup operations\n");
// cache.cleanUp();
printCache(cache);
}
}
Output
Elements in the cache are
Employee [id=1, firstName=Krishna, lastName=Gurram, expiryTime=5]
Employee [id=2, firstName=Gopi, lastName=Battu, expiryTime=8]
Employee [id=3, firstName=Saurav, lastName=Sarkar, expiryTime=15]
About to sleep for 6 seconds
Elements in the cache are
Employee [id=2, firstName=Gopi, lastName=Battu, expiryTime=8]
Employee [id=3, firstName=Saurav, lastName=Sarkar, expiryTime=15]
About to sleep for 10 seconds
Elements in the cache are
Employee [id=3, firstName=Saurav, lastName=Sarkar, expiryTime=15]
上面的代码在创建Caffeine缓存对象时,调用expireAfter
来自定义缓存的过期策略。在实现expireAfterCreate
方法中,根据缓存元素中设置的过期时间,来单独为每个缓存元素动态设置过期时间。
根据打印的输出可以可以验证,当程序休眠6秒后,由于id=1的元素值的过期时间是5s,所以它先过期被从缓存中删除。当程序再次休眠4s后,此时id=2的元素值也超过了设置的缓存时间,因此也被从缓存中删除。此时,缓存中只存在一个id=3的唯一一个元素。