gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-12-01 13:57:30 25 4
gpt4 key购买 nike

我有一个java应用程序,如果我使用单线程并且一次只处理一张图像,它可以很好地压缩多页tiff图像。然而,一旦我使用线程池使其成为多线程,事情就开始出错。例如,如果我有一个包含 2 个 TIFF 图像的目录,并使用 2 个线程运行我的应用程序,则第一个图像会被很好地压缩,并且所有页面都在那里。但第二个总是会丢失除第一页之外的所有页面。

如果我从目录中删除其中一个图像(无论是哪一个),然后使用单个线程再次运行它,它会很好地压缩两个图像的图像,并且每个图像都会保持其页数。

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

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();
}

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

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());
}
}

另外,如果重要的话,这是我的可运行类:

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 类及其 super ImageHandler 类中的几乎所有方法都同步时,我一生都无法弄清楚为什么这些线程会互相困惑。

知道是什么原因造成的吗?

最佳答案

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

executor.execute(worker);

将开始在线程池中的线程之一中处理您的任务。然而,这个调用不会被阻塞。之后您立即执行:

executor.shutdown();

这会阻止添加任何新作业并设置有序关闭的标志,但不会立即对您的代码产生影响。下一行有效果:

executor.awaitTermination(60, TimeUnit.SECONDS);

这将等待最多 60 秒让所有线程完成,但会在 60 秒后继续(请参阅 doc ):

Blocks until all tasks have completed execution after a shutdown request, or the timeout occurs, or the current thread is interrupted, whichever happens first.

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

尝试增加超时,看看这是否是问题所在,或者除此之外是否还有其他问题。要彻底解决您的问题,请使用 ExecutorCompletionService等待所有任务完成。

关于压缩TIFF图像时的Java线程同步问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19550274/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com