首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >压缩TIFF图像时的Java线程同步问题

压缩TIFF图像时的Java线程同步问题
EN

Stack Overflow用户
提问于 2013-10-23 19:05:04
回答 1查看 173关注 0票数 0

我有一个java应用程序,可以压缩多页tiff图像,如果我使用一个线程,一次只能做一个图像。然而,当我用线程池多线程时,事情就开始出错了。例如,如果我有一个目录,其中包含两个TIFF图像,并且运行我的应用程序有两个线程,那么第一个图像就会很好地压缩,所有的页面都在那里。但除了第一页外,第二页总是会丢失每一页。

如果我从目录中删除其中一个图像(哪个不重要),然后用一个线程再次运行它,它会对这两个图像进行良好的压缩,并且每个图像保持其页面计数。

我的压缩方法在一个名为TiffHandler的类中,具体方法如下:

代码语言:javascript
复制
public synchronized void compress() throws IOException
{
    System.out.println("NUMpAGES: " + numPages);
    if(this.getSrcImageFile().length()<SIZE_THRESHOLD){
        this.closeAllStreams();
        return;
    }
    this.initOutStreams();
    this.setImageEncoder(ImageCodec.createImageEncoder("tiff", this.getOutputStream(), null));
    int compressionAlgorithm;
    if(bitDepth == 1 || bitDepth == 8)
    {
        /*Cant use JPEG_TTN2 with images that have less than 8-bit samples/only have a bit-depth of 1.*/   
        compressionAlgorithm = TIFFEncodeParam.COMPRESSION_DEFLATE;
        encodeParams.setCompression(compressionAlgorithm); //redundant with line above
    }
    else
    {

        System.out.println("Attempting to compress using JPEG_TTN2 with bit depth: " + bitDepth);
        compressionAlgorithm = TIFFEncodeParam.COMPRESSION_JPEG_TTN2;
        encodeParams.setCompression(compressionAlgorithm); //redundant with line above
    }
    this.setImageEncoder(ImageCodec.createImageEncoder("tiff", this.getOutputStream(), encodeParams));
    Vector vector = new Vector();
    if(numPages == 1){
         for(int i = 0; i < numPages - 1; i ++) //i < bufferedImages.length OLD
         {
              System.out.println(i);
              vector.add((bufferedImages[i]));
         } 
    }else{
         System.out.println("Using second case");
         for(int i = 0; i < numPages; i ++)
         {
              System.out.println("Adding to vector image for file " + this.getSrcImagePath() + " " + i);
              vector.add((bufferedImages[i]));
         }            
    }

    System.out.println("Buffered Images size: " + bufferedImages.length);

    Iterator vecIter = vector.iterator();
    if(numPages > 1){
        vecIter.next();
    }

    encodeParams.setExtraImages(vecIter);
    this.getImageEncoder().encode(bufferedImages[0]);
    closeAllStreams();
}

创建和运行线程的具体方法如下:

代码语言:javascript
复制
public void compressImages() throws IOException{

    ExecutorService executor = Executors.newFixedThreadPool(NTHREADS);
    for(int i = 0; i < TIFFList.size(); i ++)
    {
        TiffHandler newTiffHandler = new TiffHandler(TIFFList.get(i).getPath(), TIFFList.get(i).getPath());
        Runnable worker = new ImgCompressor(newTiffHandler);
        executor.execute(worker);
        currCount++;
        if(currCount%2 == 0)
        {
            updateProgress(currCount);
            System.out.println((double)currCount/(double)imageCount);
        }else if(i == TIFFList.size() - 1){
            updateProgress(currCount);
        }

    }
    executor.shutdown();
    try 
    {
        executor.awaitTermination(60, TimeUnit.SECONDS);
    } 
    catch (InterruptedException ex) 
    {
        Logger.getLogger(FJImageCompressor.class.getName()).log(Level.SEVERE, null, ex);
    }finally{
        this.mainProgBar.setString("Complete");
        this.mainProgBar.update(this.mainProgBar.getGraphics());
    }
}

此外,如果这很重要,下面是我的可运行类:

代码语言:javascript
复制
import java.io.*;
public class ImgCompressor implements Runnable {

    private ImageHandler mainHandler;

    public ImgCompressor(ImageHandler mainHandler){
        this.mainHandler = mainHandler;
    }

    @Override
    public void run() {
        try{
            mainHandler.compress();
        }catch(IOException e){
            e.printStackTrace();
        }

    }

}

我无法理解为什么这些线程在TiffHandler类中的几乎所有方法以及它的超级ImageHandler类都是同步的情况下相互混淆。

知道是什么导致的吗?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2013-10-23 19:17:43

在完成之前,您正在关闭线程池。

代码语言:javascript
复制
executor.execute(worker);

将开始在线程池中的一个线程中执行任务。然而,这一呼吁不会被阻止。之后你立即做了:

代码语言:javascript
复制
executor.shutdown();

这将防止添加任何新作业,并设置一个用于有序关闭的标志,但否则在代码中不会立即生效。下一行的效果是:

代码语言:javascript
复制
executor.awaitTermination(60, TimeUnit.SECONDS);

这将等待60秒才能完成所有线程,但在60秒后继续(请参见文档):

块,直到所有任务在关闭请求后完成执行,或超时发生,或当前线程被中断,以先发生者为准。

注意,线程池将继续运行,直到所有任务都完成为止,但是您在代码中过早地访问了结果。

尝试增加超时时间,看看这是否是问题所在,或者除了这个问题之外,还有其他问题。要想清晰地解决问题,请使用ExecutorCompletionService等待所有任务完成。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/19550274

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档