我在javax.imageio规范中看到,线程安全并不是一个目标,尽管我已经看到了几个在web环境中使用ImageIO.read()和ImageIO.write()上传/消毒图像的例子。
所以,我的问题是,不管规范怎么说,ImageIO线程安全吗?
发布于 2015-08-26 20:20:56
至少在我的一个环境中,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特定的。但以下是环境保护局的细节。在我看来失败的地方:
发布于 2014-10-10 13:16:04
是的,静态方法ImageIO.read(...)和write(...)是线程安全的。
规范中说明https://docs.oracle.com/javase/8/docs/technotes/guides/imageio/spec/goals.fm2.html的部分需要在上下文中阅读。规范实际上说的是,单独的ImageReader、ImageWriter或ImageInputStream/ImageOutputStream实现不需要关注线程安全(因此,客户端代码永远不应该假定它们是线程安全的)。只要你遵守这条规则,你就安全了。但是,请注意,规范的同一部分还指出:
..。同一插件类的多个实例必须能够同时操作。
规范的这一部分没有特别讨论ImageIO的静态方法,但是上面的引用意味着tese方法是线程安全的,因为ImageIO.read(...)和write(...)为每次调用创建了新的ImageInputStream/ImageOutputStream和ImageReader/ImageWriter实例。所以,这并不是真正的“不管规范怎么说”。
ImageIO类由其他几个安全使用的静态方法组成,类本身(大部分是*)是无状态的。如果不是这样的话,那就没什么用了.
*)在类创建时填充ImageIO的ImageIO实例,并在调用scanForPlugins()方法时重新初始化。如果两个线程同时调用插件,您可能会遇到问题(即插件可能无法正确注册),但作为客户端代码控制,可以很容易地避免这种情况发生。还有每个线程组CacheInfo,但是它的使用似乎是正确同步的。
免责声明,我没有编写规范,但这是我的解释(我在无数多线程应用程序中使用了ImageIO,并自己编写了十几个ImageReader和ImageWriter插件)。
https://stackoverflow.com/questions/26297491
复制相似问题