7

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?

Alex
  • 327
  • 1
  • 3
  • 12

2 Answers2

9

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:

  • OS : Ubuntu 14.04
  • java -version :
    java version "1.8.0_33"
    Java(TM) SE Runtime Environment (build 1.8.0_33-b05)
    Java HotSpot(TM) Client VM (build 25.33-b05, mixed mode)
preston.m.price
  • 646
  • 1
  • 10
  • 17
  • ImageIO.write is also not thread-safe. Invokling it from multiple threads results in artifacts: https://i.imgur.com/tiOZjQ7.png – Luna Dec 31 '15 at 00:15
  • 2
    This answer refers to a known OpenJDK bug, [JDK-6986863] (https://bugs.openjdk.java.net/browse/JDK-6986863), unfortunately still not fixed (at the time of this posting). It's a (threading?) issue that exists in the Java2D color management subsystem, outside of `ImageIO` though. – Harald K May 23 '17 at 10:44
  • It happens on `Windows` too so this is still a problem in `Java 8` at least and should be worked around. – BullyWiiPlaza Sep 12 '18 at 18:00
  • Happens on OSX with JDK 8 – Downhillski Dec 24 '18 at 00:29
  • This [bug is finally fixed](https://bugs.openjdk.java.net/browse/JDK-6986863) now, in JDK 17. – Harald K Sep 21 '21 at 06:46
8

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).

Harald K
  • 26,314
  • 7
  • 65
  • 111
  • For my understanding are you saying using a concrete `ImageReader` is not safe, but using `ImageIO.read()` is safe? – Alex Oct 10 '14 at 14:31
  • It's completely safe to use an ImageReader, even multiple instances at the same time. They are just not thread-safe, in the meaning, you can't share a *single instance* between *multiple threads* (ie. an ImageReader has state). – Harald K Oct 10 '14 at 15:04
  • Understood, but can you use one `ImageIO` method concurrently in multiple threads? – Alex Oct 10 '14 at 16:06
  • Yes, most methods (like `read`, `write` etc) can be (and trust me, they are) used concurrently. – Harald K Oct 10 '14 at 16:40
  • 1
    I suspected ImageIO was not thread safe because my JVM kept crashing when I upped my code to 8 threads. But then I found that the problem was with other stuff in my per-thread code: it was my OpenCL processing of each image that was not thread safe. When I put a synchronisation block around my OpenCL stuff there was no problem with ImageIO on many threads. – Adam Gawne-Cain Jan 30 '21 at 12:02