I see in the javax.imageio
spec that thread-safety is not a goal, despite I've seen several examples using ImageIO.read()
and ImageIO.write()
for uploading/sanitizing images in a web environment.
So, my question is, despite what the spec says, is ImageIO
thread-safe?
ImageIO is not thread safe (or at least one of it's plugins is not), in at least one of my environments. I am in the process of debugging an issue where png and jpg files don't get loaded correctly (sometimes solid gray, sometimes inverted colors, sometimes random colors, etc) when ImageIO.read() is invoked from multiple threads. I also occasionally get ConcurrentModificationExceptions like:
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)
I am not able to replicate this behavior in all environments so it may be JVM specific. But here are the details of the env. where I see it fail:
TLDR; Yes, the static methods ImageIO.read(...)
and write(...)
are thread safe.
The part of the specification that says "thread safety is not a goal" needs to be read in context. What the spec actually says, is that individual ImageReader
, ImageWriter
or ImageInputStream/ImageOutputStream
implementations do not need to be concerned with thread safety (and as a result, client code should never assume they are thread safe). As long as you live by this rule, you are safe. Note however, that the same part of the spec also states that:
[...] it must be possible for multiple instances of the same plug-in class to operate simultaneously.
This part of the specification does not discuss the static methods of ImageIO
especially, but the above quote implies that tese methods are thread safe, as ImageIO.read(...)
and write(...)
creates new instances of ImageInputStream
/ImageOutputStream
and ImageReader
/ImageWriter
for each invocation. So, it's not really "despite what the spec says".
The ImageIO
class consists of several other static methods that are safe to use, and the class itself is (mostly*) stateless. If it didn't work this way, it wouldn't really be of much use...
*) The IIORegistry
instance of ImageIO
is populated at class creation time, and re-initialized whenever the scanForPlugins()
method is invoked. You might run into problems (i.e. plugins might not be correctly registered) if two threads invoke it the same time, but as client code control where/when it happens, you can easily avoid that. There's also the per thread group CacheInfo
, but its usage seems to be properly synchronized.
Disclaimer, I didn't write the spec, but this is my interpretation (and I have used ImageIO
in countless, multithreaded applications, as well as written a dozen or so ImageReader
and ImageWriter
plugins myself).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With