简体   繁体   中英

Tracking concurrent file processing in Java web app

I have a Java 1.5 web application that converts arbitrary PDF files to images. It takes too long to process all pages of even a single PDF in one shot, so I want to process pages on demand.

I've read that I can use an ExecutorService to launch/queue the image generation operation in a new thread as the HTTP requests for particular pages arrive. How do I ensure that I'm not queueing duplicate operations (eg, two users request the same page from the same PDF) without resorting to a single thread executor? How can I use something like a synchronized list to track which images the worker threads are processing (or, what type of synchronization mechanism can help me track this)?

You can use a ConcurrentSkipListSet or ConcurrentHashMap to track which PDFs have been processed (and are presumably cached) or are currently being processed. Use a ConcurrentLinkedQueue for your PDF-to-image requests; when a worker thread pulls a request off of the queue it adds it to the Set/Map, if the add succeeds then the thread processes the request, if the add fails then the request was already in the container.

You could use a ConcurrentHashMap<String, Future<String>> with a PDF identifier (eg file path or so) as the key and a task representing the conversion operation itself as the value.

The putIfAbsent method of ConcurrentHashMap can deal with the question of compare-and-set operation and the isDone method of Future can indicate whether the conversion has finished or not.

When putIfAbsent returns null , it means that the conversion task for a given PDF did not yet exist, thus you need to invoke ExecutorService.submit(Callable<T> task) to fire up your newly created conversion task; otherwise you omit this step and wait for the already existing task to finish.

Mockup:

Future<String> conversionTask = ... // blah
Future<String> existingTask = conversions.putIfAbsent(pdfId, conversionTask);
if (existingTask != null) {
    conversionTask = existingTask;
}
// Either way, conversion is scheduled by now.

The ExecutorService takes care of queueing your conversion requests.

Once a conversion completes, you can retrieve the result via Future<V>.get() method.

Please note that spawning threads within a Java EE application is not permitted by the specification. A common approach is to separate your asynchronous processing as a JMS service - Apache Camel can help you here.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM