4

我实际上是在尝试使用 itext 将 tiff 文件转换为 pdf,这相当简单。但据我TiffImage.getTiffImage所知,执行较大的文件需要花费大量时间。

我的要求是使用FutureTaskExecutorService提供多线程解决方案。这是我当前的代码:

import java.util.concurrent.Callable;

import com.itextpdf.text.Image;
import com.itextpdf.text.pdf.RandomAccessFileOrArray;
import com.itextpdf.text.pdf.codec.TiffImage;

public class ProcessTiffImage implements Callable<Image>{

    RandomAccessFileOrArray tiffFile;
    int pageNo;

    public ProcessTiffImage(RandomAccessFileOrArray tiffFile, int pageNo){
        this.tiffFile = tiffFile;
        this.pageNo = pageNo;
    }

    public Image call() throws Exception {
        Image image = TiffImage.getTiffImage(tiffFile, pageNo);

        return image;

    }

}

并且转换方法是

public boolean convert(Document document) {

        int numOfThreads = Runtime.getRuntime().availableProcessors()  ;
        ExecutorService service = Executors.newFixedThreadPool(numOfThreads );
        List<FutureTask<Image>> taskList = new ArrayList<FutureTask<Image>>();
        List<Image> imageList = new ArrayList<Image>();

        for (int page = 1; page <= numOfPages; page++) {
            FutureTask<Image> futureTask = new FutureTask<Image>(new ProcessTiffImage(tiffFile, page));
            taskList.add(futureTask);
            service.execute(futureTask);
        }

        try {
            // Wait until all results are available
            for (FutureTask<Image> future : taskList) {

                imageList.add(future.get());
            }

        } catch (InterruptedException ex) {
            ex.printStackTrace();
        } catch (ExecutionException ex) {
            ex.printStackTrace();
        }

        service.shutdown();


        boolean success = generatePdf(document, imageList);
        return success;
    }

但我得到了一个NullPointerExceptionat future.get()。问题是执行没有等待 TiffImage.getTiffImage(tiffFile, pageNo) 完成。因此我无法创建图像列表。任何帮助将不胜感激。

堆栈跟踪

java.util.concurrent.ExecutionException: java.lang.NullPointerException
    at java.util.concurrent.FutureTask.report(FutureTask.java:122)
    at java.util.concurrent.FutureTask.get(FutureTask.java:188)
    at com.app.convertor.TiffParser.convert(TiffParser.java:107)
    at com.app.start.TiffToPdf.main(TiffToPdf.java:40)
Caused by: java.lang.NullPointerException
Caused by: java.lang.NullPointerException
    at com.itextpdf.text.pdf.codec.TIFFDirectory.getFieldAsLong(TIFFDirectory.java:467)
    at com.itextpdf.text.pdf.codec.TIFFDirectory.getFieldAsLong(TIFFDirectory.java:477)
    at com.itextpdf.text.pdf.codec.TiffImage.getTiffImage(TiffImage.java:124)
    at com.itextpdf.text.pdf.codec.TiffImage.getTiffImage(TiffImage.java:106)
    at com.app.processor.ProcessTiffImage.call(ProcessTiffImage.java:20)
    at com.app.processor.ProcessTiffImage.call(ProcessTiffImage.java:1)
    at java.util.concurrent.FutureTask.run(FutureTask.java:262)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
    at java.lang.Thread.run(Thread.java:744)
4

2 回答 2

3

不要Future自己创建,请执行者为你创建,(即:提交Callable

List<Future<Image>> taskList = new ArrayList<Future<Image>>();

 for (int page = 1; page <= numOfPages; page++) {
     Future<Image> futureTask = service.submit(new ProcessTiffImage(tiffFile, page));
     taskList.add(futureTask);
 }

for (Future<Image> future : taskList) {
   imageList.add(future.get());
}

注意:考虑改用ExecutorCompletionService

于 2015-10-20T11:47:57.017 回答
1

这似乎正在发生,因为RandomAccessFileOrArray 它不是线程安全的。

您在调用中遇到的异常是future.get()调用中的潜在异常TiffImage.getTiffImage(),这似乎正在发生,因为该方法对传递的 TIFF 数据不满意。特别是,它正在寻找一些领域,但似乎它不存在。可能是图像高度或宽度?

但这种情况正在发生,因为RandomAccessFileOrArray它正在多个线程中被消耗。每次一个线程移动文件中的指针时,它就会搞砸其他线程正在做的事情。

您需要使用RandomAccessFileOrArray.createView()来获取要传递给每个线程的文件的新视图:

Image image = TiffImage.getTiffImage(tiffFile.createView(), pageNo);
于 2015-10-20T12:08:40.607 回答