在Java中缓存从inputstream读取的图像的最佳实践

在Java中缓存从inputstream读取的图像的最佳实践,java,Java,我有一个servlet,它充当获取图像的代理,从HttpURLConnection输入流中读取图像作为字节,然后将字节写入响应输出流。以下是相关的代码片段: HttpURLConnection connection = (HttpURLConnection)url.openConnection(); connection.setConnectTimeout(CONNECT_TIMEOUT); connection.setReadTimeout(READ_TIMEOUT); InputStrea

我有一个servlet,它充当获取图像的代理,从HttpURLConnection输入流中读取图像作为字节,然后将字节写入响应输出流。以下是相关的代码片段:

HttpURLConnection connection = (HttpURLConnection)url.openConnection();
connection.setConnectTimeout(CONNECT_TIMEOUT);
connection.setReadTimeout(READ_TIMEOUT);

InputStream in = connection.getInputStream();
OutputStream out = resp.getOutputStream();

byte[] buf = new byte[1024];
int count = 0;
while ((count = in.read(buf)) >= 0) {
  out.write(buf, 0, count);
}

我想开始在代理servlet中缓存图像。我正在考虑包装字节数组并存储在映射中,但我怀疑有更好的方法。我注意到javax.imagio包,但我没有使用它的经验,也不确定它是否与这里相关。具体来说,我想了解如何存储图像,而不是缓存机制。

如果您只缓存图像,我建议将图像保留为字节数组,而不是图像。使用imageio读取图像将解压图像,并占用更多的内存空间


WeekHashMap类可能是缓存内容的最简单方法,但您无法控制从中逐出条目的方式。

如果您只缓存图像,我建议将图像保留为字节数组,而不是图像。使用imageio读取图像将解压图像,并占用更多的内存空间


WeekHashMap类可能是缓存内容的最简单方法,但您无法控制从中逐出条目的方式。

在某些有限的情况下,哈希映射可以工作。但你需要考虑:

(1) 当缓存变为“满”时,如何从内存中清除缓存的图像(不管您如何定义它——可能是您希望用于缓存的最大内存量)。 (2) 如何处理并发性。 (3) 与此相关,您将如何处理这样的情况:客户端A请求一个映像,然后客户端B请求相同的映像,而该映像仍在加载到客户端A的缓存中

(1)的一个非常简单的解决方案可能是始终存储对映像数据的软引用,并让JVM决定何时清除它们(记住,它可以在您无法控制的时候任意清除它们)。否则,您需要制定某种策略(先进先出、最早访问的图像、最小/最大的图像等,如果我们必须再次加载图像,则需要最长时间解码的图像等)——只有您知道自己的数据和用法,因此您必须找到正确的策略

对于(2),一般会帮助你解决问题;您可以决定在更高级的情况下使用显式锁和其他并发实用程序

对于(3),Goetz等人提出的一个相当优雅的解决方案是劫持Future类。在地图中,将未来存储到缓存对象(或“缓存条目”对象)。如果请求者发现未来已经添加到映射中,那么它可以调用get()并等待另一个线程完成数据缓存。(您可以通过显式锁定和条件实现类似的效果,但未来需要为您做一些工作。)


另外,我同意海报上的说法,他说你可能想把图片以原始编码的形式储存起来。但从您的代码来看,我认为这可能是您一直以来的意图。

在某些有限的情况下,哈希映射可以工作。但你需要考虑:

(1) 当缓存变为“满”时,如何从内存中清除缓存的图像(不管您如何定义它——可能是您希望用于缓存的最大内存量)。 (2) 如何处理并发性。 (3) 与此相关,您将如何处理这样的情况:客户端A请求一个映像,然后客户端B请求相同的映像,而该映像仍在加载到客户端A的缓存中

(1)的一个非常简单的解决方案可能是始终存储对映像数据的软引用,并让JVM决定何时清除它们(记住,它可以在您无法控制的时候任意清除它们)。否则,您需要制定某种策略(先进先出、最早访问的图像、最小/最大的图像等,如果我们必须再次加载图像,则需要最长时间解码的图像等)——只有您知道自己的数据和用法,因此您必须找到正确的策略

对于(2),一般会帮助你解决问题;您可以决定在更高级的情况下使用显式锁和其他并发实用程序

对于(3),Goetz等人提出的一个相当优雅的解决方案是劫持Future类。在地图中,将未来存储到缓存对象(或“缓存条目”对象)。如果请求者发现未来已经添加到映射中,那么它可以调用get()并等待另一个线程完成数据缓存。(您可以通过显式锁定和条件实现类似的效果,但未来需要为您做一些工作。)


另外,我同意海报上的说法,他说你可能想把图片以原始编码的形式储存起来。但从您的代码来看,我认为这可能是您一直想要的。

这不是对
WeakHashMap
的良好使用。请参阅以了解原因的解释。提示:只要没有人引用您的键,您的值就会消失。这不是
WeakHashMap
的好用法。请参阅以了解原因的解释。提示:一旦没有人持有对键的引用,您的值就会消失。