Java中的多线程JPEG图像处理

Java中的多线程JPEG图像处理,java,multithreading,image,Java,Multithreading,Image,在多线程环境中,借助图像IO在Java中读取JPEG图像时遇到问题。只有当多个线程尝试读取图像时才会出现问题 症状从不正确的配置文件加载到异常: java.awt.color.CMMException: LCMS error 13: Couldn't link the profiles 无论我如何阅读图像,都可以通过ImageIO.read或使用ImageReader 源数据(图像)是完全隔离和不可变的 此问题可能与以下方面有关: 及 问题是有没有其他方法可以通过多线程读取带有ImageIO

在多线程环境中,借助图像IO在Java中读取JPEG图像时遇到问题。只有当多个线程尝试读取图像时才会出现问题

症状从不正确的配置文件加载到异常:

java.awt.color.CMMException: LCMS error 13: Couldn't link the profiles
无论我如何阅读图像,都可以通过ImageIO.read或使用ImageReader

源数据(图像)是完全隔离和不可变的

此问题可能与以下方面有关: 及

问题是有没有其他方法可以通过多线程读取带有ImageIO的JPEG文件。在ImageIO中,共享我无法控制的图像颜色配置文件的可变状态似乎存在问题。我看到的唯一解决方案是在JVM级别完全隔离它,这听起来是个坏主意

我使用的是Oracle JDK 8u25。更改JDK更新版本对这个问题没有影响(不是主要版本),我不能在不重写大块代码的情况下使用JDK 7

参考代码

ImageInputStream input = new MemoryCacheImageInputStream(inputStream);
Iterator<ImageReader> readers = ImageIO.getImageReaders(input);

if (!readers.hasNext()) {
    throw new IllegalArgumentException("No reader for: " + dataUuid.toString());
}

ImageReader reader = readers.next();
try {
    reader.setInput(input);
    BufferedImage image = reader.read(0, reader.getDefaultReadParam());
ImageInputStream输入=新内存CacheMageInputStream(inputStream);
迭代器读卡器=ImageIO.getImageReaders(输入);
如果(!readers.hasNext()){
抛出新的IllegalArgumentException(“没有读卡器:“+dataUuid.toString()”);
}
ImageReader=readers.next();
试一试{
reader.setInput(输入);
BuffereImage image=reader.read(0,reader.getDefaultReadParam());

在JVM开始时添加一个钩子。在钩子中,只需放置:

Class.forName("javax.imageio.ImageIO");
这将强制类加载器加载该类并执行它需要的任何静态初始化。我认为您的问题是该类正在加载到一个线程上,而第二个线程正在尝试使用ImageIO,这会导致在颜色配置文件上获得的锁(或lackof锁)发生冲突

编辑:你也可以将这一行添加到你的主线。确保这是你调用的第一行。 ImageIO不是负责颜色空间初始化的类

Class.forName("java.awt.color.ICC_ColorSpace");
Class.forName("sun.java2d.cmm.lcms.LCMS");

这个技巧很难。

我昨天在ImageIO上遇到了类似的多线程问题,花了一整天的时间试图找到一个解决方案(JDK 8u31 Win64)。即使我没有收到LCMS异常,但我使用ImageIO读取的JPEG将具有完全不同的颜色。这仅发生在带有嵌入式颜色配置文件的JPEG上,并且仅在多线程中使用ImageIO时发生。不总是。大约有50%的时间。如果它正常启动,则它将继续正确读取所有图像est的图像,但如果它不会-所有其余的也将被打破。所以这是明确的颜色配置文件读取/转换同步问题

这里提出的类加载技巧对我的情况没有帮助

最终的解决方案是使用ImageIO jpeg插件。我已经在多个线程中用数千个jpeg进行了测试,到目前为止没有问题

更新


TwelveMonkeys插件并没有完全解决这个问题,仍然出现异常。帮助的是通过设置系统属性
system.setProperty(“sun.java2d.cmm”,“sun.java2d.cmm.kcms.kcms服务提供者”)恢复到旧的Kodak CMS

自从JRE 1.8.031在一台Win7机器上使用PDFRenderer以来,我遇到了同样的错误。Class.forName的建议并没有解决这个问题。但是我可以找到另一个窍门:将以下代码放在主方法的顶部,错误就消失了:

         try {
             ColorSpace.getInstance(ICC_ColorSpace.CS_sRGB).toRGB(new float[]{0, 0, 0});
         } catch (Exception e) {
             e.printStackTrace();
         }

希望这也能帮助其他人。到目前为止,我无法确认此黑客是否解决了问题。该问题似乎与当前版本的OpenJDK中的惰性实例有关。

感谢您的anwser,遗憾的是它没有解决问题,但我认为您让我走上了正确的道路。结果仍然不一致,例外on被抛出,但如果未抛出异常,它会更改配置文件选择。是的,添加sun.java2d.cmm.lcms.lcms帮助,您可以修改anwser吗?它可以帮助其他人。