JDK-4480705 : Java SWING EventQueue thread deadlocks with animated GIFs
  • Type: Bug
  • Component: client-libs
  • Sub-Component: javax.swing
  • Affected Version: 1.3.0,1.3.1,1.4.0
  • Priority: P2
  • Status: Resolved
  • Resolution: Fixed
  • OS: solaris_8,windows_nt
  • CPU: x86,sparc
  • Submitted: 2001-07-17
  • Updated: 2004-09-16
  • Resolved: 2001-08-24
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
Other Other
1.3.1_03 03Fixed 1.4.0Fixed
Related Reports
Duplicate :  
Duplicate :  
Description
Customer Problem Description:
----------------------------
The UI for our product is written in Java using SWING. We have run into
the following problem :

Our swing-based java application hangs when we are trying to raise a 
JOptionPane to the user.  The EventQueue thread seems to be
deadlocked with two other threads, which are for animaged gif's elsewhere on
the GUI.

Here's the thread dump:

Full thread dump:

"Image Animator 0" daemon prio=3 tid=0x5e0ed0 nid=0x4f8 waiting on monitor
[0xebe81000..0xebe819e0]
	at java.lang.Object.wait(Native Method)
	at java.awt.MediaTracker.waitForID(MediaTracker.java:632)
	at javax.swing.ImageIcon.loadImage(ImageIcon.java:226)
	at javax.swing.ImageIcon.<init>(ImageIcon.java:161)
	at javax.swing.JLabel.getDisabledIcon(JLabel.java:409)
	at javax.swing.JLabel.imageUpdate(JLabel.java:806)
	at sun.awt.image.ImageWatched.newInfo(ImageWatched.java:58)
	at
sun.awt.image.ImageRepresentation.imageComplete(ImageRepresentation.java:626
)
	at sun.awt.image.ImageDecoder.imageComplete(ImageDecoder.java:138)
	at sun.awt.image.GifFrame.dispose(GifImageDecoder.java:637)
	at sun.awt.image.GifImageDecoder.readImage(GifImageDecoder.java:479)
	at
sun.awt.image.GifImageDecoder.produceImage(GifImageDecoder.java:223)
	at
sun.awt.image.InputStreamImageSource.doFetch(InputStreamImageSource.java:257
)
	at sun.awt.image.ImageFetcher.fetchloop(ImageFetcher.java:217)
	at sun.awt.image.ImageFetcher.run(ImageFetcher.java:185)

"Image Animator 0" daemon prio=3 tid=0x6878d8 nid=0x1fc waiting on monitor
[0xebf81000..0xebf819e0]
	at java.lang.Object.wait(Native Method)
	at java.awt.MediaTracker.waitForID(MediaTracker.java:632)
	at javax.swing.ImageIcon.loadImage(ImageIcon.java:226)
	at javax.swing.ImageIcon.<init>(ImageIcon.java:161)
	at javax.swing.JLabel.getDisabledIcon(JLabel.java:409)
	at javax.swing.JLabel.imageUpdate(JLabel.java:806)
	at sun.awt.image.ImageWatched.newInfo(ImageWatched.java:58)
	at
sun.awt.image.ImageRepresentation.imageComplete(ImageRepresentation.java:626
)
	at sun.awt.image.ImageDecoder.imageComplete(ImageDecoder.java:138)
	at sun.awt.image.GifFrame.dispose(GifImageDecoder.java:637)
	at sun.awt.image.GifImageDecoder.readImage(GifImageDecoder.java:479)
	at
sun.awt.image.GifImageDecoder.produceImage(GifImageDecoder.java:223)
	at
sun.awt.image.InputStreamImageSource.doFetch(InputStreamImageSource.java:257
)
	at sun.awt.image.ImageFetcher.fetchloop(ImageFetcher.java:217)
	at sun.awt.image.ImageFetcher.run(ImageFetcher.java:185)

"Thread-163" prio=6 tid=0x5d87b0 nid=0xb8 waiting on monitor
[0xf0101000..0xf01019e0]
	at java.lang.Thread.sleep(Native Method)
	at
com.xerox.controller.jobGUI.ListJobs$ListJobsWorker.doWork(ListJobs.java:276
)
	at
com.xerox.controller.jobGUI.ListJobs$ListJobsWorker.construct(ListJobs.java:
209)
	at com.xerox.controller.util.SwingWorker$2.run(SwingWorker.java:145)
	at java.lang.Thread.run(Thread.java:484)

"Thread-35" prio=6 tid=0x521ee0 nid=0x37 waiting on monitor
[0xeb981000..0xeb9819e0]
	at java.lang.Thread.sleep(Native Method)
	at
com.xerox.controller.jobGUI.ListJobs$ListJobsWorker.doWork(ListJobs.java:276
)
	at
com.xerox.controller.jobGUI.ListJobs$ListJobsWorker.construct(ListJobs.java:
209)
	at com.xerox.controller.util.SwingWorker$2.run(SwingWorker.java:145)
	at java.lang.Thread.run(Thread.java:484)

"Thread-34" prio=6 tid=0x521c78 nid=0x36 waiting on monitor
[0xeba81000..0xeba819e0]
	at java.lang.Thread.sleep(Native Method)
	at
com.xerox.controller.jobGUI.ListJobs$ListJobsWorker.doWork(ListJobs.java:276
)
	at
com.xerox.controller.jobGUI.ListJobs$ListJobsWorker.construct(ListJobs.java:
209)
	at com.xerox.controller.util.SwingWorker$2.run(SwingWorker.java:145)
	at java.lang.Thread.run(Thread.java:484)

"Screen Updater" prio=5 tid=0x23c8a0 nid=0x1d waiting on monitor
[0xf0501000..0xf05019e0]
	at java.lang.Object.wait(Native Method)
	at java.lang.Object.wait(Object.java:420)
	at sun.awt.ScreenUpdater.nextEntry(ScreenUpdater.java:76)
	at sun.awt.ScreenUpdater.run(ScreenUpdater.java:95)

"Thread-2" prio=5 tid=0x281d0 nid=0x1 runnable [0..0xffbeebc8]

"Thread-1" prio=5 tid=0xdfeb0 nid=0x11 runnable [0xf0201000..0xf02019e0]
	at java.net.PlainSocketImpl.socketAccept(Native Method)
	at java.net.PlainSocketImpl.accept(PlainSocketImpl.java:413)
	at java.net.ServerSocket.implAccept(ServerSocket.java:243)
	at java.net.ServerSocket.accept(ServerSocket.java:222)
	at JRPC.JRPCServer.run(JRPCServer.java:131)
	at java.lang.Thread.run(Thread.java:484)

"Thread-0" prio=5 tid=0xe0dc8 nid=0x10 runnable [0xf0301000..0xf03019e0]
	at java.net.PlainDatagramSocketImpl.receive(Native Method)
	at java.net.DatagramSocket.receive(DatagramSocket.java:392)
	at JRPC.ServerUDP.run(ServerUDP.java:41)
	at java.lang.Thread.run(Thread.java:484)

"TimerQueue" daemon prio=5 tid=0x2456a8 nid=0xf waiting on monitor
[0xf0401000..0xf04019e0]
	at java.lang.Object.wait(Native Method)
	at javax.swing.TimerQueue.run(TimerQueue.java:233)
	at java.lang.Thread.run(Thread.java:484)

"AWT-Motif" prio=6 tid=0x1bf0c0 nid=0xd runnable [0xf0601000..0xf06019e0]
	at sun.awt.motif.MToolkit.run(Native Method)
	at java.lang.Thread.run(Thread.java:484)

"SunToolkit.PostEventQueue-0" prio=5 tid=0x1b50d0 nid=0xc waiting on monitor
[0xf0701000..0xf07019e0]
	at java.lang.Object.wait(Native Method)
	at java.lang.Object.wait(Object.java:420)
	at sun.awt.PostEventQueue.run(SunToolkit.java:497)

"AWT-EventQueue-0" prio=5 tid=0x1b3880 nid=0xb waiting on monitor
[0xf07ff000..0xf08019e0]
	at java.lang.Object.wait(Native Method)
	at java.awt.MediaTracker.waitForID(MediaTracker.java:632)
	at javax.swing.ImageIcon.loadImage(ImageIcon.java:226)
	at javax.swing.ImageIcon.<init>(ImageIcon.java:209)
	at javax.swing.LookAndFeel$1.createValue(LookAndFeel.java:275)
	at javax.swing.UIDefaults.get(UIDefaults.java:145)
	at javax.swing.MultiUIDefaults.get(MultiUIDefaults.java:46)
	at javax.swing.UIDefaults.getIcon(UIDefaults.java:250)
	at javax.swing.UIManager.getIcon(UIManager.java:476)
	at
javax.swing.plaf.basic.BasicOptionPaneUI.getIconForType(BasicOptionPaneUI.ja
va:508)
	at
javax.swing.plaf.basic.BasicOptionPaneUI.getIcon(BasicOptionPaneUI.java:490)
	at
javax.swing.plaf.basic.BasicOptionPaneUI.addIcon(BasicOptionPaneUI.java:471)
	at
javax.swing.plaf.basic.BasicOptionPaneUI.createMessageArea(BasicOptionPaneUI
.java:295)
	at
javax.swing.plaf.basic.BasicOptionPaneUI.installComponents(BasicOptionPaneUI
.java:124)
	at
javax.swing.plaf.basic.BasicOptionPaneUI.installUI(BasicOptionPaneUI.java:92
)
	at javax.swing.JComponent.setUI(JComponent.java:325)
	at javax.swing.JOptionPane.setUI(JOptionPane.java:1425)
	at javax.swing.JOptionPane.updateUI(JOptionPane.java:1447)
	at javax.swing.JOptionPane.<init>(JOptionPane.java:1410)
	at javax.swing.JOptionPane.showOptionDialog(JOptionPane.java:670)
	at com.xerox.controller.frameworks.Message.postIt(Message.java:91)
	at com.xerox.controller.frameworks.Message.postIt(Message.java:117)
	at
com.xerox.controller.frameworks.Message.postQuestion(Message.java:235)
	at
com.xerox.controller.jobGUI.JobPropsManager.delete(JobPropsManager.java:443)
	at
com.xerox.controller.jobGUI.JobMenuHandler.actionPerformed(JobMenuHandler.ja
va:97)
	at
javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:1450)
	at
javax.swing.AbstractButton$ForwardActionEvents.actionPerformed(AbstractButto
n.java:1504)
	at
javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:3
78)
	at
javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:250)
	at javax.swing.AbstractButton.doClick(AbstractButton.java:279)
	at
javax.swing.plaf.basic.BasicMenuItemUI$MouseInputHandler.mouseReleased(Basic
MenuItemUI.java:886)
	at java.awt.Component.processMouseEvent(Component.java:3715)
	at java.awt.Component.processEvent(Component.java:3544)
	at java.awt.Container.processEvent(Container.java:1165)
	at java.awt.Component.dispatchEventImpl(Component.java:2593)
	at java.awt.Container.dispatchEventImpl(Container.java:1214)
	at java.awt.Component.dispatchEvent(Component.java:2497)
	at
java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:2452)
	at
java.awt.LightweightDispatcher.processMouseEvent(Container.java:2217)
	at java.awt.LightweightDispatcher.dispatchEvent(Container.java:2126)
	at java.awt.Container.dispatchEventImpl(Container.java:1201)
	at java.awt.Window.dispatchEventImpl(Window.java:912)
	at java.awt.Component.dispatchEvent(Component.java:2497)
	at java.awt.EventQueue.dispatchEvent(EventQueue.java:333)
	at
java.awt.EventDispatchThread.pumpOneEvent(EventDispatchThread.java:103)
	at
java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:93)
	at java.awt.EventDispatchThread.run(EventDispatchThread.java:84)

"Signal Dispatcher" daemon prio=10 tid=0x9d338 nid=0x9 runnable [0..0]

"Finalizer" daemon prio=8 tid=0x9a418 nid=0x7 waiting on monitor
[0xfd181000..0xfd1819e0]
	at java.lang.Object.wait(Native Method)
	at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:149)
	at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:164)
	at
java.lang.ref.Finalizer$FinalizerWorker$FinalizerThread.run(Finalizer.java:1
20)

"Reference Handler" daemon prio=10 tid=0x98ae0 nid=0x6 waiting on monitor
[0xfd281000..0xfd2819e0]
	at java.lang.Object.wait(Native Method)
	at java.lang.Object.wait(Object.java:420)
	at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:129)

"VM Thread" prio=5 tid=0x97e80 nid=0x4 runnable

"VM Periodic Task Thread" prio=10 tid=0x9ca48 nid=0x8 waiting on monitor

----------

Essentially, I think the question boils down to:

[1] How does one properly get rid of an animated GIF. In particular, how does
    one clean up after it so that the SWING thread used for animating the GIF
    is terminated and does not tie up Swing's eventQueue thread?
    
[2] What is the proper coding practice to have multiple animated GIFs running
    concurrently. This is a follow on to [1] above as the UI team has serialized
    the activation (running) of multiple animated GIFs.
    
Below please find a tar file containing sample code to reproduce the problem. To 
recreate the problem, please take the following steps:

% java IconTest

Once the GUI is launched, click on the tile labeled 'OptionPane...'. The GUI 
will lock up.

The work around the developer has put in is to null out the animated GIF icon 
instance before subsequent reuse. You can invoke that behavior in the test code 
as follows,

% java IconTest -fix

With the above, the GUI should not hang and a new 'Error' pop up window should 
be displayed, which is what is desired.

One last final question:

[3] Looks like we tripped across a bug? The above work around mitigates the number of ocurrences. However, we still run against the problem.

We are see'ng this problem in all JDK releases 1.3, 1.3.1, 1.4 Beta
on Solaris. We see this problem on win32 platform too.

===============================================================================
Verified in MB91

###@###.### 2002-01-15
===============================================================================

Comments
CONVERTED DATA BugTraq+ Release Management Values COMMIT TO FIX: 1.3.1_03 merlin-beta3 FIXED IN: 1.3.1_03 merlin-beta3 INTEGRATED IN: 1.3.1_03 merlin-beta3 VERIFIED IN: merlin-rc1
17-09-2004

EVALUATION I think this is an issue with the use of images and MediaTracker. As such, I'm going to pass it to 2D for their evaluation. eric.hawkes@eng 2001-07-18 The test application in the bugreport does the following: - creates two ImageIcons with animated gifs: IM1 and IM2. - creates two JLabels (L1, L2) with these icons - starts up two timer threads T1 and T2 which swap the icons in the labels every half a second: T1: L1.setIcon(IM2)/L1.setIcon(IM1) T1: L2.setIcon(IM1)/L2.setIcon(IM2) - there is one more button in the app which triggers creation of one more ImageIcon with another (non-animated, but it doesn't matter) image, IM3. When this application is started, the labels start to display animated images, but actually they display only one frame of each image (Problem 1). When the application tries to load the third image, it locks up for good (Problem 2). This is reproducible at least with 1.3, 1.3.1 and 1.4 (b75). Here is a typical stack trace (only threads that we'll be interested in are shown, full stack trace is attached): "Image Animator 1" daemon prio=3 tid=0x2b1b00 nid=0x13 waiting on monitor [ef380000..ef381a28] at java.lang.Object.wait(Native Method) - waiting on <f447aae8> (a java.awt.MediaTracker) at java.awt.MediaTracker.waitForID(MediaTracker.java:634) - locked <f447aae8> (a java.awt.MediaTracker) at javax.swing.ImageIcon.loadImage(ImageIcon.java:228) - locked <f447aae8> (a java.awt.MediaTracker) at javax.swing.ImageIcon.<init>(ImageIcon.java:163) at javax.swing.JLabel.getDisabledIcon(JLabel.java:417) at javax.swing.JLabel.imageUpdate(JLabel.java:876) at sun.awt.image.ImageWatched.newInfo(ImageWatched.java:58) at sun.awt.image.ImageRepresentation.imageComplete(ImageRepresentation.java:648) at sun.awt.image.ImageDecoder.imageComplete(ImageDecoder.java:138) at sun.awt.image.GifFrame.dispose(GifImageDecoder.java:673) at sun.awt.image.GifImageDecoder.readImage(GifImageDecoder.java:480) at sun.awt.image.GifImageDecoder.produceImage(GifImageDecoder.java:223) at sun.awt.image.InputStreamImageSource.doFetch(InputStreamImageSource.java:260) at sun.awt.image.ImageFetcher.fetchloop(ImageFetcher.java:217) at sun.awt.image.ImageFetcher.run(ImageFetcher.java:185) "Image Animator 0" daemon prio=8 tid=0x2b1550 nid=0x12 waiting on monitor [f3501000..f3501a28] at java.lang.Object.wait(Native Method) - waiting on <f447aae8> (a java.awt.MediaTracker) at java.awt.MediaTracker.waitForID(MediaTracker.java:634) - locked <f447aae8> (a java.awt.MediaTracker) at javax.swing.ImageIcon.loadImage(ImageIcon.java:228) - locked <f447aae8> (a java.awt.MediaTracker) at javax.swing.ImageIcon.<init>(ImageIcon.java:163) at javax.swing.JLabel.getDisabledIcon(JLabel.java:417) at javax.swing.JLabel.imageUpdate(JLabel.java:876) at sun.awt.image.ImageWatched.newInfo(ImageWatched.java:58) at sun.awt.image.ImageRepresentation.setDimensions(ImageRepresentation.java:126) at sun.awt.image.ImageDecoder.setDimensions(ImageDecoder.java:65) at sun.awt.image.GifImageDecoder.readImage(GifImageDecoder.java:554) at sun.awt.image.GifImageDecoder.produceImage(GifImageDecoder.java:223) at sun.awt.image.InputStreamImageSource.doFetch(InputStreamImageSource.java:260) at sun.awt.image.ImageFetcher.fetchloop(ImageFetcher.java:217) at sun.awt.image.ImageFetcher.run(ImageFetcher.java:185) "AWT-EventQueue-0" prio=6 tid=0x276690 nid=0x11 waiting on monitor [f3600000..f3601a28] at java.lang.Object.wait(Native Method) - waiting on <f447aae8> (a java.awt.MediaTracker) at java.awt.MediaTracker.waitForID(MediaTracker.java:634) - locked <f447aae8> (a java.awt.MediaTracker) at javax.swing.ImageIcon.loadImage(ImageIcon.java:228) - locked <f447aae8> (a java.awt.MediaTracker) at javax.swing.ImageIcon.<init>(ImageIcon.java:85) at javax.swing.ImageIcon.<init>(ImageIcon.java:105) at IconTest$OPListener.actionPerformed(IconTest.java:65) at javax.swing.AbstractButton.fireActionPerformed(AbstractButton.java:1770) at javax.swing.AbstractButton$ForwardActionEvents.actionPerformed(AbstractButton.java:1823) at javax.swing.DefaultButtonModel.fireActionPerformed(DefaultButtonModel.java:422) at javax.swing.DefaultButtonModel.setPressed(DefaultButtonModel.java:260) at javax.swing.plaf.basic.BasicButtonListener.mouseReleased(BasicButtonListener.java:261) at java.awt.Component.processMouseEvent(Component.java:4992) at java.awt.Component.processEvent(Component.java:4791) at java.awt.Container.processEvent(Container.java:1383) at java.awt.Component.dispatchEventImpl(Component.java:3501) at java.awt.Container.dispatchEventImpl(Container.java:1440) at java.awt.Component.dispatchEvent(Component.java:3363) at java.awt.LightweightDispatcher.retargetMouseEvent(Container.java:3195) at java.awt.LightweightDispatcher.processMouseEvent(Container.java:2906) at java.awt.LightweightDispatcher.dispatchEvent(Container.java:2842) at java.awt.Container.dispatchEventImpl(Container.java:1426) at java.awt.Window.dispatchEventImpl(Window.java:1568) at java.awt.Component.dispatchEvent(Component.java:3363) at java.awt.EventQueue.dispatchEvent(EventQueue.java:448) at java.awt.EventDispatchThread.pumpOneEventForHierarchy(EventDispatchThread.java:193) at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:147) at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:141) at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:133) at java.awt.EventDispatchThread.run(EventDispatchThread.java:101) Here are some facts which will help in understanding what's going on here: - ImageIcon class uses one static MediaTracker object for all ImageIcon instances - All images added to the MediaTracker with the same ID - 0 Now, lets see what happens when the application first starts up: Main Thread: new ImageIcon("IM1") loadImage() waitForID(0,0) - the image is loaded, waitForID exits new ImageIcon("IM2") loadImage() waitForID(0,0) - the image is loaded, waitForID exits Timer1.start(); -> creates Timer thread T1 Timer2.start(); -> creates Timer thread T2 frame.setVisible(true) Main thread dies Event Queue Thread (EQT): paintComponent(L1) drawImage(IM1, L1) - L1 is the ImageObserver for IM1. Since IM1 is an animated gif this call starts an Animator thread (A1) which spins and notifies the ImageObserver (Label1 in this case) when the next frame is ready by calling L1.imageUpdate(). JLabel overrides imageUpdate() from Component: it first checks if the image that is updated is of any interest for this particular label: the check is if (!updatedImage == getIcon() && !updatedImage == getDisabledIcon()) { return false; // not interested } else return super.imageUpdate(); // causes repaint A1 starts paintComponent(L2) drawImage(IM2, L2) - A2 starts Note: GifFrame.dispose is called when the next animated gif frame is ready A1: A2: T1: T2: GifFrame.dispose GifFrame.dispose L1.setIcon(IM2) L1.setIcon(IM2) L1.imageUpdate(IM1) L2.imageUpdate(IM2) <updatedImage in both cases != getIcon since T1 and T2 changed the icons in the labels> L1.getDisabledIcon() L2.getDisabledIcon() <getDisabledIcon uses FilteredImageSource for creating a grayed version of the defaultImage, but it uses an original image's ImageProducer to get the bits.> new ImageIcon(grayIM2) new ImageIcon(grayIM1) loadImage(grayIM2) loadImage(grayIM2) MT.waitForID(0,0) MT.waitForID(0,0) MT.getStatus() MT.getStatus() - in both cases MediaTracker.getStatus() returns LOADING since there were no updates from the producers. wait() wait() So now both animator threads are waiting for the updates (which cause notify()) to continue. And no update will come since A1 is waiting for updates from IM2 (which are to be produced by the animator thread A2), and A2 is waiting for updates from IM1 (produced by animator thread A1). We've got a deadlock. Timer threads T1 and T2 and EQT contunue working: T1 and T2 setting icons back and forth and causing repaint, and EQT causes repainting the last frame from each image. Now lets see what happens when user presses button which causes loading of another image. EQT: ImageIcon.loadImage MT.addImage(newImage, 0) MT.waitForID(0, 0) getStatus(0) - since the id of the image is 0 (same as all others being tracked by this MediaTracker), it will return (COMPLETE | LOADING) because of the way it calculates the status: for each image being tracked status |= getStatus(image) So even though this last image had been loaded waitForID won't return because it's waiting for other images with this id (0) to be loaded. So the EQT hangs there forever, blocking the application. This bug exposes two problems in Swing: 1. loading of the images from JLabel.imageUpdate() (and AbstractButton.imageUpdate()). This problem has some performance implications as well: for example, the disabled (and a bunch of others in AbstractButton) icon will be loaded even if they're not really needed. 2. ImageIcon registers all images in it's only MediaTracker with the same id. So, for example, if somebody is loading two images, a huge one and a small one, they'll have to wait until the huge one is loaded: MediaTracker.waitForID will not return until all images with same ids are loaded. Not to mention a potential hang in case when one of the image fetchers hangs for some reason (since one of the images will never load, the rest will be waiting infinitely). The fix for the first problem would probably be : instead of calling getIcon(), getDisabledIcon() - just check the appropriate fields: i.e in JLabel.imageUpdate(image) : if (image != defaultIcon || image != disabledIcon) { return false } The fix for the second one - a static int counter could be introduced which would be incremented for each image so eash image would have a unique (mod MAXINT) id. I've tried these fixes and they seem to work fine. Since this is not a 2D bug, I'm reassigning it to Swing. ###@###.### 2001-08-15 I've implemented the changes as outlined above by Dmitri. ###@###.### 2001-08-24
15-08-2001

WORK AROUND Here is the workaround: set the disabled icon for all the labels at the time of creation (and then every time you change the default icon). You can use the same image as for the default icon. I've attached a modified minimal testcase which reproduces the problem. Uncomment lines // l.setDisabledIcon(printing); // l2.setDisabledIcon(faulted); to workaround the problem. This prevents loading of the image in getDisaledIcon() called from imageUpdate, which happens on the Animator thread (which is the cause of the bug). This works for all affected jdks. Note that AbstractButton has the same problem, but it will try to load much more images, it calls getIcon() getPressedIcon() getDisabledIcon() getSelectedIcon() getDisabledSelectedIcon(), getRolloverIcon() getRolloverSelectedIcon() ###@###.### 2001-08-14
14-08-2001