Skip to main content

JVM "Hangs" on multit hreaded Image resizer

1 reply [Last post]
nick_s
Offline
Joined: 2004-10-06

We are trying to convert jpg images to a specific size. Because the huge amount of pictures we decided to use the multi threaded approach with a backport of the Java 1.5 Concurrency package. (We are still using 1.4 for production)

The application in our test environment runs on Java 1.5.0_05 and Apache Tomcat 5.5.20 on Linux.

Now for the real problem. I'm running the following code with 4 threads. I've read that the Graphics2D code is not thread safe, so I've synchronized it. However, the convert method hangs on the next thread dump:

"pool-1-thread-3" prio=1 tid=0x8c9b81a0 nid=0x1e56 runnable [0x8a533000..0x8a5337f0]
at sun.java2d.loops.ScaledBlit.Scale(Native Method)
at sun.java2d.pipe.DrawImage.scaleSurfaceData(DrawImage.java:850)
at sun.java2d.pipe.DrawImage.renderImageScale(DrawImage.java:505)
at sun.java2d.pipe.DrawImage.tryCopyOrScale(DrawImage.java:287)
at sun.java2d.pipe.DrawImage.transformImage(DrawImage.java:171)
at sun.java2d.pipe.DrawImage.transformImage(DrawImage.java:947)
at sun.java2d.pipe.ValidatePipe.transformImage(ValidatePipe.java:212)
at sun.java2d.SunGraphics2D.drawImage(SunGraphics2D.java:2969)
at sun.java2d.SunGraphics2D.drawRenderedImage(SunGraphics2D.java:2392)
at test.ImageCallable.convert(ImageCallable.java:90)

The relevant code of the ImageCallable:

private static final Object GRAPHICS_MUTEX = new Object();

static {
ImageIO.setUseCache(false);
}

private boolean convert(final ImageFormat imageFormat, final BufferedImage imageSource, final File destinationFile) {
Dimension imageSize = imageFormat.getDimension();

log.debug("Scaling image '" + relativeImageFile + "' to " + imageSize.toString());
boolean success = true;
try {
BufferedImage bufferedImageDst = new BufferedImage(imageSize.width,
imageSize.height, BufferedImage.TYPE_INT_RGB);

double width = new Double(bufferedImageDst.getWidth()).doubleValue() /
new Double(imageSource.getWidth()).doubleValue();
double height = new Double(bufferedImageDst.getHeight()).doubleValue() /
new Double(imageSource.getHeight()).doubleValue();

AffineTransform transform = AffineTransform.getScaleInstance(width, height);

//Native code behind drawRenderedImage is not thread safe.
synchronized (GRAPHICS_MUTEX) {
Graphics2D g = bufferedImageDst.createGraphics();
g.drawRenderedImage(imageSource, transform); // <- the problem line
g.dispose();
}

success = ImageIO.write(bufferedImageDst, imgFileSuffix.toUpperCase(), destinationFile);
} catch (Exception e) {
log.warn("Error scaling image '" + relativeImageFile + "' to " + imageSize.toString());
success = false;
}
return success;
}

Has anybody any clue what is going wrong, and how I can fix it?

Reply viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
Jim Graham

[I sent this out a few days ago, but my mailer replied to the wrong
header address so it never went anywhere - sending again to the list in
hopes it can still clarify some things...jim]

Hi Nick,

java2d@javadesktop.org wrote:
> Now for the real problem. I'm running the following code with 4 threads. I've read that the Graphics2D code is not thread safe, so I've synchronized it. However, the convert method hangs on the next thread dump:

A given Graphics2D object can only be used on a single thread at a time,
but you can be using separate Graphics2D objects concurrently in
separate threads as much as you want. Thus, the MUTEX in your code
below is unnecessary.

> "pool-1-thread-3" prio=1 tid=0x8c9b81a0 nid=0x1e56 runnable [0x8a533000..0x8a5337f0]
> at sun.java2d.loops.ScaledBlit.Scale(Native Method)
> at sun.java2d.pipe.DrawImage.scaleSurfaceData(DrawImage.java:850)
> at sun.java2d.pipe.DrawImage.renderImageScale(DrawImage.java:505)
> at sun.java2d.pipe.DrawImage.tryCopyOrScale(DrawImage.java:287)
> at sun.java2d.pipe.DrawImage.transformImage(DrawImage.java:171)
> at sun.java2d.pipe.DrawImage.transformImage(DrawImage.java:947)
> at sun.java2d.pipe.ValidatePipe.transformImage(ValidatePipe.java:212)
> at sun.java2d.SunGraphics2D.drawImage(SunGraphics2D.java:2969)
> at sun.java2d.SunGraphics2D.drawRenderedImage(SunGraphics2D.java:2392)
> at test.ImageCallable.convert(ImageCallable.java:90)

Can you isolate the specific scaling call into an isolated test case?
Since the thread is runnable, I'm guessing that the specific request to
scale an image in this case is running into an infinite loop (or perhaps
it is asking for a huge scale that is just taking a long time?)

> //Native code behind drawRenderedImage is not thread safe.
> synchronized (GRAPHICS_MUTEX) {
> Graphics2D g = bufferedImageDst.createGraphics();
> g.drawRenderedImage(imageSource, transform); // <- the problem line
> g.dispose();
> }

Note that the use of this particular Graphics2D object all occurs on a
single thread so it does not need to be synchronized...

...jim

===========================================================================
To unsubscribe, send email to listserv@java.sun.com and include in the body
of the message "signoff JAVA2D-INTEREST". For general help, send email to
listserv@java.sun.com and include in the body of the message "help".