前言:
最近公司的服务调用系统,需要把放进Redis中的一部分数据,直接放进内存中进行取读。这样,可以加快取读速度并且还可以减配Redis集群的服务器配置。一开始,我打算有手写一个带过期的Map。但是,自我感觉技术菜鸟,手写可能想不周全,更容易出问题。所以我在网络上寻找一番,找到了ExpiringMap这个开源架包。简单看了一下ExpiringMap的文档,应该可以支持业务改造。下面,我介绍一下ExpiringMap的使用。
正文:
一、ExpiringMap简介:
它具有高性能、低开销、零依赖、线程安全、使用ConcurrentMa的实现过期entries等优点。主要特点包括:过期策略、可变有效期、最大尺寸、侦听器过期、延迟输入加载、过期自省。
二、项目地址:
https://github.com/jhalterman/expiringmap
三、使用:
0.引入架包依赖:
<dependency>
<groupId>net.jodah</groupId>
<artifactId>expiringmap</artifactId>
<version>0.5.9</version>
</dependency>
1.简单使用,设置5秒的过期时间:
/**
* 简单使用,设置5秒的过期时间
*
* @throws InterruptedException
*/
private static void test1() throws InterruptedException {
ExpiringMap<String, String> map = ExpiringMap.builder()
// 设置过期时间和过期时间单位
.expiration(5, TimeUnit.SECONDS)
.build();
map.put("1", "测试");
map.put("2", "测试");
Thread.sleep(6000);
System.out.println(map); // {}
}
2.过期策略的使用(CREATED、ACCESSED):
/**
* 过期策略的使用:
* CREATED: 在每次更新元素时,过期倒计时清零
* ACCESSED: 在每次访问元素时,过期倒计时清零
*
* @throws InterruptedException
*/
private static void test2() throws InterruptedException {
// 使用默认的CREATED策略:
System.out.println("----使用默认的CREATED策略:----");
ExpiringMap<String, String> map = ExpiringMap.builder()
.expirationPolicy(ExpirationPolicy.CREATED)
.expiration(2, TimeUnit.SECONDS)
.build();
// -- 测试CREATED策略,访问的情况
map.put("1", "测试");
Thread.sleep(1000);
System.out.println(map.get("1")); // 测试
Thread.sleep(1001);
System.out.println(map.get("1")); // null
// -- 测试CREATED策略,更新的情况
map.put("2","测试");
Thread.sleep(1000);
System.out.println(map.get("2")); // 测试
map.put("2","测试1");
Thread.sleep(1000);
System.out.println(map.get("2")); // 测试1
Thread.sleep(900);
System.out.println(map.get("2")); // 测试1
Thread.sleep(200);
System.out.println(map.get("2")); // null
// 使用默认的ACCESSED策略:
System.out.println("----使用默认的ACCESSED策略:----");
ExpiringMap<String, String> map1 = ExpiringMap.builder()
.expirationPolicy(ExpirationPolicy.ACCESSED)
.expiration(2, TimeUnit.SECONDS)
.build();
// -- 测试ACCESSED策略,访问的情况
map1.put("1", "测试");
Thread.sleep(1000);
System.out.println(map1.get("1")); // 测试
Thread.sleep(1100);
System.out.println(map1.get("1")); // 测试
Thread.sleep(2100);
System.out.println(map1.get("1")); // null
// 只是访问时,过期倒计时清零
map1.put("2","测试");
Thread.sleep(1000);
System.out.println(map1); // {2=测试}
Thread.sleep(1100);
System.out.println(map1); // {}
}
3.可变有效期,即单独为每个entity设置过期时间和策略:
/**
* 可变有效期,即单独为每个entity设置过期时间和策略:
*
* @throws InterruptedException
*/
private static void test3() throws InterruptedException {
ExpiringMap<String, String> map = ExpiringMap.builder()
.variableExpiration()
.expiration(2, TimeUnit.SECONDS)
.build();
map.put("1", "测试", ExpirationPolicy.CREATED, 1, TimeUnit.SECONDS);
map.put("2", "测试", ExpirationPolicy.CREATED, 2, TimeUnit.SECONDS);
map.put("3", "测试", ExpirationPolicy.CREATED, 999, TimeUnit.MILLISECONDS);
map.put("4", "测试", ExpirationPolicy.CREATED, 1003, TimeUnit.MILLISECONDS);
Thread.sleep(1002);
System.out.println(map); // {2=测试, 4=测试}
}
4.最大值的使用:
/**
* 最大值的使用:
* Map中映射数目超过最大值的大小时,先过期第一个要过期的entity过期
*
* @throws InterruptedException
*/
private static void test4() throws InterruptedException {
ExpiringMap<String, String> map = ExpiringMap.builder()
.maxSize(3)
.expiration(2, TimeUnit.SECONDS)
.build();
map.put("1", "测试");
map.put("2", "测试");
map.put("3", "测试");
System.out.println(map); // {1=测试, 2=测试, 3=测试}
map.put("4", "测试");
System.out.println(map); // {2=测试, 3=测试, 4=测试}
}
5. 过期侦听器的使用:
/**
* 过期侦听器的使用:当entity过期时,可以通知过期侦听器:
*
* @throws InterruptedException
*/
private static void test5() throws InterruptedException {
ExpiringMap<String, String> map = ExpiringMap.builder()
// 同步过期提醒
.expirationListener((key, value) -> remindExpiration(key, value))
// 异步过期提醒
.asyncExpirationListener((key, value) -> remindAsyncExpiration(key, value))
.expiration(2, TimeUnit.SECONDS)
.build();
map.put("1", "测试");
while (true){
}
}
/**
* 过期提醒
*
* @param key
* @param value
*/
private static void remindExpiration(Object key, Object value) {
System.out.println("过期提醒,key: " + key + " value: " + value);
}
/**
* 异步过期提醒
*
* @param key
* @param value
*/
private static void remindAsyncExpiration(Object key, Object value) {
System.out.println("异步过期提醒,key: " + key + " value: " + value);
}
6.懒加载的使用:
/**
* 懒加载的使用:put方法时不创建对象,在调用get方法时自动去创建对象
*
* @throws InterruptedException
*/
private static void test6() throws InterruptedException {
ExpiringMap<String, Student> map = ExpiringMap.builder()
.expiration(2, TimeUnit.SECONDS)
.entryLoader(name -> new Student(name))
.build();
System.out.println(map); // {}
map.get("hanxiaozhang");
System.out.println(map); // {hanxiaozhang=com.hanxiaozhang.expiringmap.ExpiringMapTest$Student@5d6f64b1}
}
7. 其他:
/**
* 其他:
*
* @throws InterruptedException
*/
private static void test7() throws InterruptedException {
ExpiringMap<String, String> map = ExpiringMap.builder()
.expiration(2, TimeUnit.SECONDS)
.build();
map.put("1", "测试");
// 查看剩余过期时间:
long remainExpiration = map.getExpectedExpiration("1");
System.out.println("查看剩余过期时间:" + remainExpiration); // 查看剩余过期时间:1970
// 查看设置过期时间:
long setExpiration = map.getExpiration("1");
System.out.println("查看设置过期时间:" + setExpiration); // 查看设置过期时间:2000
// 重置过期时间
map.resetExpiration("1");
System.out.println("查看剩余过期时间:" + map.getExpectedExpiration("1")); // 查看剩余过期时间:1999
}