Java 缓存或多重映射用于基于日期的缓存过期?
背景:我正在为订购系统开发分析系统。每天大约有100000份订单,分析需要在过去N(比如说100)个月内运行。相关数据存储在内存中。N天后,所有订单都将从内存缓存中收回,过去一整天都将被收回。可以创建或更新订单Java 缓存或多重映射用于基于日期的缓存过期?,java,caching,guava,multimap,Java,Caching,Guava,Multimap,背景:我正在为订购系统开发分析系统。每天大约有100000份订单,分析需要在过去N(比如说100)个月内运行。相关数据存储在内存中。N天后,所有订单都将从内存缓存中收回,过去一整天都将被收回。可以创建或更新订单 传统方法将使用ConcurrentHashMap。每天,表示过去N天以上日期的键的值都将被删除。但是,当然,使用番石榴的全部目的是为了避免这种情况。编辑:将Map更改为ConcurrentHashMap,请参见问题末尾了解基本原理 有了番石榴系列,MultiMap会更简单。逐出类似,是显
ConcurrentHashMap
。每天,表示过去N天以上日期的键的值都将被删除。但是,当然,使用番石榴的全部目的是为了避免这种情况。编辑:将Map
更改为ConcurrentHashMap
,请参见问题末尾了解基本原理MultiMap
会更简单。逐出类似,是显式实现的Cache
实现看起来很吸引人(毕竟,我正在实现一个缓存),但我不确定驱逐选项。逐出每天只发生一次,最好从缓存外部启动,我不希望缓存必须检查订单的期限。我甚至不确定缓存是否会使用多重映射,我认为在这种情况下,多重映射是合适的数据结构EDIT2:只是被绊倒了。看起来多重映射不是并发的。我认为最简单的方法是在订单记录中包含订单日期。(我想它已经是一个字段了)因为你每天只需要清理缓存一次,所以它不需要非常高效,只是相当及时 e、 g 对于100000个订单,我预计这需要花费10毫秒,而不是在午夜的一个安静的时间内发生。
顺便说一句:如果您的医嘱ID是按时间排序的,那么您可以使其更有效 您是否考虑过使用某种排序的排序列表?它将允许你拉条目,直到你击中一个足够新鲜的停留。当然,这是假设这是你的主要功能。如果您最需要的是使用hashmap的O(1)访问,那么我的答案不适用。我在这里既不使用
缓存,也不使用多映射。虽然我喜欢并使用这两种方法,但在这里收获不多
- 您希望手动逐出条目,因此
Cache
的功能在这里没有真正使用
- 您正在考虑使用
ConcurrentHashMap
,从某种意义上讲,它比多映射
更强大
如果我考虑到不同的逐出标准,如果我想随时丢失它的任何条目,我会使用缓存
您可能会发现您需要一个ConcurrentMap
或ConcurrentMap
或其他任何东西。这可能是由多映射
以某种方式管理的,但我认为它会变得更复杂而不是更简单
我会问自己,“在这里使用Cache
或Multimap
有什么好处?”。在我看来,普通的ConcurrentMap
提供了您所需要的一切
1我决不是说番石榴会这样。相反,如果没有逐出原因(容量、过期等),它的工作方式就像一个ConcurrentMap
。只是你所描述的感觉更像是一个映射
而不是缓存
参见(缓存
是MapMaker
生成的并发映射
的继承者),还有。关于编辑#2:你可以用指定的多映射来支持一个同步(线程安全的)多映射。@Xaerxess谢谢,我必须测试它的性能;我担心它不会像ConcurrentHashMap那么好,在这种情况下,我必须回到使用JDK类(即问题中的方法1)。订单日期是关键,因此在方法1中,整个订单集合(存储在队列中)被逐出。但问题更多的是关于#2对#3。我认为你是对的;早些时候,我看到了这样一条评论:“注意:如果您不需要缓存的功能,那么ConcurrentHashMap的内存效率更高——但是用任何旧的ConcurrentMap复制大多数缓存功能是极其困难或不可能的。”虽然缓存可以返回ConcurrentMap,但我认为不值得使用它。
public class Main {
static class Order {
final long time;
Order(long time) {
this.time = time;
}
public long getTime() {
return time;
}
}
final Map<String, Order> orders = new LinkedHashMap<String, Order>();
public void expireOrdersOlderThan(long dateTime) {
for (Iterator<Order> iter = orders.values().iterator(); iter.hasNext(); )
if (iter.next().getTime() < dateTime)
iter.remove();
}
private void generateOrders() {
for (int i = 0; i < 120000; i++) {
orders.put("order-" + i, new Order(i));
}
}
public static void main(String... args) {
for (int t = 0; t < 3; t++) {
Main m = new Main();
m.generateOrders();
long start = System.nanoTime();
for (int i = 0; i < 20; i++)
m.expireOrdersOlderThan(i * 1000);
long time = System.nanoTime() - start;
System.out.printf("Took an average of %.3f ms to expire 1%% of entries%n", time / 20 / 1e6);
}
}
}
Took an average of 9.164 ms to expire 1% of entries
Took an average of 8.345 ms to expire 1% of entries
Took an average of 7.812 ms to expire 1% of entries