我有一个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());
}
}
此外,如果重要,这是我的runnable类:
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类全部同步时,这些线程互相混乱。
知道可能导致这种情况的原因吗?
答案 0 :(得分:1)
在完成之前,您正在关闭线程池。
executor.execute(worker);
将开始在线程池中的一个线程中处理您的任务。但是,此调用不会阻止。之后你马上做:
executor.shutdown();
这可以防止添加任何新作业,并为有序关闭设置标志,但在您的代码中没有立即生效。下一行有效:
executor.awaitTermination(60, TimeUnit.SECONDS);
这将等待所有线程完成后最多60秒,但在60秒后继续(参见doc):
阻止所有任务在关闭请求之后完成执行,或发生超时,或者当前线程被中断,以先发生者为准。
请注意,线程池将一直运行,直到所有任务都完成,但是您在代码中过早地访问结果。
尝试增加超时以查看这是否是问题,或者除此之外还有其他错误。要获得问题的清晰解决方案,请使用ExecutorCompletionService等待所有任务完成。