Java 如何缓存文件句柄?

Java 如何缓存文件句柄?,java,caching,clojure,Java,Caching,Clojure,我有一个应用程序希望保持打开许多文件:它定期接收客户机请求 说“向文件X添加一些数据”,最好已经打开该文件,并且该文件 标头部分已解析,因此写入速度很快。但是,保持打开这么多文件是非常困难的 对操作系统不是很好,如果我们的数据存储需求增长,这可能变得不可能 所以我想要一个“给我这个文件句柄,如果它没有被缓存就打开”函数,以及一些进程 用于自动关闭(例如)五分钟内未写入的文件。对于 缓存文件句柄的具体情况是在短时间内写入,这可能就足够了, 但这似乎是一个足够普遍的问题,应该有类似“给我一个名为X的

我有一个应用程序希望保持打开许多文件:它定期接收客户机请求 说“向文件X添加一些数据”,最好已经打开该文件,并且该文件 标头部分已解析,因此写入速度很快。但是,保持打开这么多文件是非常困难的 对操作系统不是很好,如果我们的数据存储需求增长,这可能变得不可能

所以我想要一个“给我这个文件句柄,如果它没有被缓存就打开”函数,以及一些进程 用于自动关闭(例如)五分钟内未写入的文件。对于 缓存文件句柄的具体情况是在短时间内写入,这可能就足够了, 但这似乎是一个足够普遍的问题,应该有类似“给我一个名为X的对象, “如果可能的话,从缓存”和“我现在已经处理完对象X,所以让它有资格被逐出5个” 从现在起几分钟”

看起来它可能适合这个 目的,但目的是相当缺乏和 没有提供关于如何使用它的具体线索。它的TTLCache看起来很有前途,但也很有吸引力 不清楚如何使用它依赖于垃圾收集来逐出项目,所以我无法干净地关闭 资源,当我准备使其过期时

当然,我可以自己滚,但是有很多棘手的地方,我相信我会得到一些 事情有点微妙的错误,所以我希望有人能给我指出这一点的实现 功能。我的代码是clojure,但是如果
这就是可以找到最佳实现的地方。

操作系统有一些限制:

SortedMapcache=newtreemap();
cache.put(新日期(),文件);
定时器=新定时器(真);
timer.scheduleAtFixedRate(任务,60*1000L,60*1000L);
要清除缓存:如果缓存的使用时间>5分钟,请先删除缓存,然后重复此操作,直到首次使用时间>5分钟。

签出

  • 您可以向
    get
    方法提供一个
    Callable
    (或
    CacheLoader
    )来实现“如果句柄被缓存,则返回它,否则打开,则缓存并返回它”语义
  • 您可以配置定时逐出,例如
  • 您可以注册以在移除时关闭句柄
使用
CacheLoader
,从链接的Guava页面稍微修改代码示例:

LoadingCache<Key, Handle> graphs = CacheBuilder.newBuilder()
   .maximumSize(100) // sensible value for open handles?
   .expireAfterAccess(5, TimeUnit.MINUTES)
   .removalListener(removalListener)
   .build(
       new CacheLoader<Key, Handle>() {
         public Handle load(Key key) throws AnyException {
           return openHandle(key);
         }
       });

RemovalListener<Key, Handle> removalListener = 
  new RemovalListener<Key, Handle>() {
    public void onRemoval(RemovalNotification<Key, Handle> removal) {
      Handle h = removal.getValue();
      h.close(); // tear down properly
    }
  };
LoadingCache-graphs=CacheBuilder.newBuilder()
.maximumSize(100)//打开句柄的合理值?
.expireAfterAccess(5,时间单位:分钟)
.removalListener(removalListener)
.建造(
新缓存加载程序(){
公共句柄加载(密钥)引发任何异常{
返回openHandle(键);
}
});
RemovalListener RemovalListener=
新RemovalListener(){
移除时的公共无效(移除通知移除){
handleh=removation.getValue();
h、 close();//正确地拆下
}
};

*免责声明*我自己并没有这样使用缓存,请确保您对此进行了明智的测试。

如果您不介意使用java,请参阅和。

这看起来非常合适,谢谢!我唯一担心的是,它看起来可能从缓存中获取一个项目,并将其保留超过到期时间,并一直积极地使用它。如果过期代码将物品撕下,则会变得危险。你知道一种从缓存中“签出一个对象”的方法吗,这样它在签回之前不会被撕毁?嗯,我想这取决于。是否会发生连续写入文件>=5分钟的情况?是否一次只能从一个请求访问缓存?请确保检查此处的文档:退出不会在到期时自动发生,而是在从缓存读取/写入缓存期间发生。也许这是好的(如果你有一个可以写很长时间的请求,那么它就不会被删除),也许是坏的,因为一次有多个请求,或者你想更早地/在后台清理句柄……请看这里:?@amalloy,这不意味着你真正想要的是“签回”对象的缓存吗,当这个缓存中的所有内容都保持打开(而不是关闭)时,在自己构建一个之前,您首先抓取这个池中的句柄。这使缓存独立于签入/签出。请尝试以下操作:
LoadingCache<Key, Handle> graphs = CacheBuilder.newBuilder()
   .maximumSize(100) // sensible value for open handles?
   .expireAfterAccess(5, TimeUnit.MINUTES)
   .removalListener(removalListener)
   .build(
       new CacheLoader<Key, Handle>() {
         public Handle load(Key key) throws AnyException {
           return openHandle(key);
         }
       });

RemovalListener<Key, Handle> removalListener = 
  new RemovalListener<Key, Handle>() {
    public void onRemoval(RemovalNotification<Key, Handle> removal) {
      Handle h = removal.getValue();
      h.close(); // tear down properly
    }
  };