必要时等待结果

时间:2009-12-10 04:39:32

标签: java multithreading

我正在创建一个包含一些动态生成图像的网页。

在我的页面请求处理中,我创建所有图像并将它们存储在内存缓存中,直到浏览器随后请求它们为止。

public class CachedImage
{
    byte[] data;
    Date created;
}

目前,我的图片缓存基本上是HashMap<Integer, CachedImage>

问题是图像生成需要时间,我想在所有图像生成完成之前开始渲染页面。

所以我想在线程池中生成图像,并在请求时返回数据(如果已准备好)或等待数据准备好然后返回。

任何人都可以为这种机制提供一个整洁的模型吗?

图像很小,我现在对将整个图像缓存在内存中的方法感到满意。

4 个答案:

答案 0 :(得分:2)

在生成页面时,为页面将显示的每个图像选择一个新的唯一标识符。这可能是一个简单的事情,就像通过递增AtomicInteger获得的数字一样,或者它可能像UUID那样更复杂,以防止用户猜测其他用户的图像URL。将这些唯一标识符放入客户端将用于检索图像的URL中。

一旦选择了图像的标识符,构造一个Callable,它将生成并返回图像,并将其提交给ThreadPoolExecutor,以便异步运行。这会返回一个Future,可用于检索结果。将未来保存在地图中,图像的标识符作为密钥。

稍后,当客户端请求图像时,您可以获取图像标识符并在地图中查找以查找关联的Future对象。在Future上调用get()将返回图像,等待生成器在必要时完成。 (如果在地图中找不到请求的标识符,则返回404错误。)

为避免使用旧图像填满服务器的内存,您可能希望在几分钟后丢弃它们。为此,每次创建任务并将其Future存储到可用图像的地图中时,您都可以将任务放入DelayQueue,以便在经过一段适当的延迟后从地图中删除该条目。使用守护程序线程从此队列中获取项目并在循环中对其进行操作。

如果生成器由于某种原因仍然在运行,那么在从地图中删除它时,对未来调用cancel(true)也是一个好主意。 (否则它会继续运行,即使图像将无法再访问。)

答案 1 :(得分:1)

听起来你需要类似未来任务的东西

http://java.sun.com/j2se/1.5.0/docs/api/java/util/concurrent/Future.html

只需启动一堆它们就可以在isDone为true时撤回结果,或者你甚至可以通过简单地调用get()来阻止等待它们完成。

答案 2 :(得分:0)

您可以从当前请求中删除整个逻辑,并使用异步请求(ajax)呈现图像,这甚至可以让您拥有“加载...”图标并控制超时等等

答案 3 :(得分:0)

当客户端(浏览器)请求网页时,它实际上并不在那时获取图像。当它呈现页面并找到标签时,浏览器会将每个图像的单独请求发回服务器。这意味着您可以在图像存在之前发送HTML页面。

因此,启动HTML响应,将图像创建请求发送到您的图像服务。当浏览器解析响应并从Web服务器请求图像时。

您可以通过让另一个线程池通过接受单个线程中的请求来响应图像请求,并在图像准备就绪时进行响应,从而提升一个档次。如果您只是尽可能快地生成图像并让您的Web服务器响应图像请求,那么您的用户将对尚未生成的图像获得404响应。