ImageIO线程安全

我在javax.imageio规范中看到线程安全不是目标,尽管我已经看到了几个使用ImageIO.read()ImageIO.write()在Web环境中上传/清理图像的示例。

所以,我的问题是,尽管规范说的是, ImageIO线程安全吗?

至少在我的一个环境中,ImageIO不是线程安全的(或至少其中一个插件不是)。 我正在调试从多个线程调用ImageIO.read()时png和jpg文件无法正确加载的问题(有时是纯灰色,有时是反色,有时是随机颜色等)。 我偶尔也会得到ConcurrentModificationExceptions,例如:

 java.util.ConcurrentModificationException at java.util.Vector$Itr.checkForComodification(Vector.java:1184) at java.util.Vector$Itr.next(Vector.java:1137) at sun.java2d.cmm.ProfileDeferralMgr.activateProfiles(ProfileDeferralMgr.java:93) at java.awt.color.ICC_Profile.getInstance(ICC_Profile.java:777) at com.sun.imageio.plugins.jpeg.JPEGImageReader.setImageData(JPEGImageReader.java:657) at com.sun.imageio.plugins.jpeg.JPEGImageReader.readImageHeader(Native Method) at com.sun.imageio.plugins.jpeg.JPEGImageReader.readNativeHeader(JPEGImageReader.java:609) at com.sun.imageio.plugins.jpeg.JPEGImageReader.checkTablesOnly(JPEGImageReader.java:347) at com.sun.imageio.plugins.jpeg.JPEGImageReader.gotoImage(JPEGImageReader.java:481) at com.sun.imageio.plugins.jpeg.JPEGImageReader.readHeader(JPEGImageReader.java:602) at com.sun.imageio.plugins.jpeg.JPEGImageReader.readInternal(JPEGImageReader.java:1059) at com.sun.imageio.plugins.jpeg.JPEGImageReader.read(JPEGImageReader.java:1039) at javax.imageio.ImageIO.read(ImageIO.java:1448) at javax.imageio.ImageIO.read(ImageIO.java:1308) at com.foo.bar.MyTestLoadThread.loadImage(MyTestLoadThread.java:241) ... at java.lang.Thread.run(Thread.java:745) 

我无法在所有环境中复制此行为,因此它可能是特定于JVM的。 但这里是环境的细节。 在哪里我看到它失败了:

  • 操作系统:Ubuntu 14.04
  • java -version:
    java版“1.8.0_33”
    Java(TM)SE运行时环境(版本1.8.0_33-b05)
    Java HotSpot(TM)客户端VM(版本25.33-b05,混合模式)

TLDR; 是的,静态方法ImageIO.read(...)write(...)是线程安全的。


规范中称“线程安全不是目标”的部分需要在上下文中阅读。 实际上说的是,单个ImageReaderImageWriterImageInputStream/ImageOutputStream实现不需要关心线程安全(因此,客户端代码永远不应该假设它们是线程安全的)。 只要你遵守这条规则,你就是安全的。 但请注意,规范的相同部分还指出:

[…]必须可以使同一插件类的多个实例同时运行。

规范的这一部分并未特别讨论ImageIO的静态方法,但上述引用暗示tese方法是线程安全的,因为ImageIO.read(...)write(...)创建了ImageInputStream / ImageOutputStream新实例和每个调用的ImageReader / ImageWriter 。 所以,它并不是“尽管规范说的”

ImageIO类由几个可以安全使用的静态方法组成,类本身(大多数是*)是无状态的。 如果它不能以这种方式工作,它就没有多大用处……

  • ImageIOIIORegistry实例在类创建时填充,并在调用scanForPlugins()方法时重新初始化。 如果两个线程同时调用它,您可能会遇到问题(即插件可能没有正确注册),但是当客户端代码控制它发生的地方/时间时,您可以轻松避免这种情况。 还有每个线程组CacheInfo ,但它的用法似乎正确同步。

免责声明,我没有编写规范,但这是我的解释(我在无数的multithreading应用程序中使用过ImageIO ,并且自己编写了十几个ImageReaderImageWriter插件)。

我检查了class级,没有州和几乎所有无国籍的class级。 (我没有检查所有function。最好在使用前检查function)

最有可能是线程安全。