我有一个 Java 1.5 Web 应用程序,可以将任意 PDF 文件转换为图像。一次处理一个 PDF 的所有页面都需要很长时间,所以我想按需处理页面。
我已经读到,ExecutorService
当特定页面的 HTTP 请求到达时,我可以使用 an 在新线程中启动/排队图像生成操作。我如何确保我不会排队重复操作(例如,两个用户从同一个 PDF 请求同一个页面)而不求助于单线程执行器?如何使用同步列表之类的东西来跟踪工作线程正在处理的图像(或者,什么类型的同步机制可以帮助我跟踪)?
我有一个 Java 1.5 Web 应用程序,可以将任意 PDF 文件转换为图像。一次处理一个 PDF 的所有页面都需要很长时间,所以我想按需处理页面。
我已经读到,ExecutorService
当特定页面的 HTTP 请求到达时,我可以使用 an 在新线程中启动/排队图像生成操作。我如何确保我不会排队重复操作(例如,两个用户从同一个 PDF 请求同一个页面)而不求助于单线程执行器?如何使用同步列表之类的东西来跟踪工作线程正在处理的图像(或者,什么类型的同步机制可以帮助我跟踪)?
您可以使用ConcurrentSkipListSet或ConcurrentHashMap来跟踪哪些 PDF 已被处理(并且可能已被缓存)或当前正在被处理。使用ConcurrentLinkedQueue处理您的 PDF 到图像请求;当工作线程从队列中拉出一个请求时,它会将其添加到 Set/Map 中,如果添加成功则线程处理该请求,如果添加失败则该请求已经在容器中。
您可以使用ConcurrentHashMap<String, Future<String>>
带有 PDF 标识符(例如文件路径等)的 a 作为键,并将表示转换操作本身的任务作为值。
的putIfAbsent
方法ConcurrentHashMap
可以处理比较和设置操作的问题,而可以指示转换是否完成的isDone
方法。Future
putIfAbsent
返回时null
,表示给定 PDF 的转换任务尚不存在,因此您需要调用ExecutorService.submit(Callable<T> task)
来启动新创建的转换任务;否则你省略这一步并等待已经存在的任务完成。
小样:
Future<String> conversionTask = ... // blah
Future<String> existingTask = conversions.putIfAbsent(pdfId, conversionTask);
if (existingTask != null) {
conversionTask = existingTask;
}
// Either way, conversion is scheduled by now.
负责将ExecutorService
您的转换请求排队。
Future<V>.get()
转换完成后,您可以通过方法检索结果。
请注意,规范不允许在 Java EE 应用程序中生成线程。一种常见的方法是将您的异步处理分离为 JMS 服务 - Apache Camel可以在这方面为您提供帮助。