JDK-6708322 : test/closed/java/awt/Focus/TemporaryLostComponentDeadlock fails
  • Type: Bug
  • Component: client-libs
  • Sub-Component: java.awt
  • Affected Version: 7
  • Priority: P3
  • Status: Closed
  • Resolution: Fixed
  • OS: linux,solaris
  • CPU: x86,sparc
  • Submitted: 2008-05-29
  • Updated: 2012-03-22
  • Resolved: 2011-05-17
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.
JDK 6 JDK 7
6u27Resolved 7 b36Fixed
Related Reports
Duplicate :  
Relates :  
Relates :  
Relates :  
Relates :  
Description
The test started to fail after integration of the fix for 6522725.
The fix introduced a new log message in XComponentPeer.requestWindowFocus method.
The message initiates calling Component.toString and then Component.getName methods.
The latter is synchronized by "this". At the same time the test itself takes a lock
on the same object (a dialog). The stack trace below shows the deadlock.

Thus the fix only revealed the problem. As AWT itself uses synchronization by
public component objects in different cases developers are better to avoid
using components as objects of synchronization.

"Thread-2" prio=10 tid=0xad8e8400 nid=0x19a7 in Object.wait() [0xad421000..0xad4220c0]
   java.lang.Thread.State: WAITING (on object monitor)
        at java.lang.Object.wait(Native Method)
        - waiting on <0xadd0ce80> (a java.awt.EventQueue$1AWTInvocationLock)
        at java.lang.Object.wait(Object.java:502)
        at java.awt.EventQueue.invokeAndWait(EventQueue.java:1015)
        - locked <0xadd0ce80> (a java.awt.EventQueue$1AWTInvocationLock)
        at java.awt.Window.doDispose(Window.java:1065)
        at java.awt.Dialog.doDispose(Dialog.java:1273)
        at java.awt.Window.dispose(Window.java:1008)
        at TemporaryLostComponentDeadlock$1.run(TemporaryLostComponentDeadlock.java:48)
        - locked <0xae1fabd8> (a java.awt.Dialog)

"AWT-EventQueue-0" prio=10 tid=0xad86f800 nid=0x19a6 waiting on condition [0xad48c000..0xad48d140]
   java.lang.Thread.State: WAITING (parking)
        at sun.misc.Unsafe.park(Native Method)
        - parking to wait for  <0xae1b4428> (a java.util.concurrent.locks.ReentrantLock$NonfairSync)
        at java.util.concurrent.locks.LockSupport.park(LockSupport.java:186)
        at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:769)
        at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued(AbstractQueuedSynchronizer.java:802)
        at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:1132)
        at java.util.concurrent.locks.ReentrantLock$NonfairSync.lock(ReentrantLock.java:214)
        at java.util.concurrent.locks.ReentrantLock.lock(ReentrantLock.java:290)
        at sun.awt.SunToolkit.awtLock(SunToolkit.java:269)
        at sun.awt.X11.XInputMethod.createXICNative(Native Method)
        at sun.awt.X11.XInputMethod.createXIC(XInputMethod.java:70)
        at sun.awt.X11InputMethod.activate(X11InputMethod.java:332)
        - locked <0xadd10488> (a sun.awt.X11.XInputMethod)
        at sun.awt.im.InputContext.activateInputMethod(InputContext.java:393)
        at sun.awt.im.InputContext.focusGained(InputContext.java:337)
        - locked <0xadd0b930> (a sun.awt.im.InputMethodContext)
        - locked <0xae1f5768> (a java.awt.Component$AWTTreeLock)
        at sun.awt.im.InputContext.dispatchEvent(InputContext.java:244)
        at sun.awt.im.InputMethodContext.dispatchEvent(InputMethodContext.java:197)
        at java.awt.Component.dispatchEventImpl(Component.java:4404)
        at java.awt.Component.dispatchEvent(Component.java:4298)
        at java.awt.KeyboardFocusManager.redispatchEvent(KeyboardFocusManager.java:1879)
        at java.awt.DefaultKeyboardFocusManager.typeAheadAssertions(DefaultKeyboardFocusManager.java:926)
        at java.awt.DefaultKeyboardFocusManager.dispatchEvent(DefaultKeyboardFocusManager.java:558)
        at java.awt.Component.dispatchEventImpl(Component.java:4342)
        at java.awt.Component.dispatchEvent(Component.java:4298)
        at sun.awt.X11.XWindow$1.run(XWindow.java:388)
        at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:235)
        at java.awt.EventQueue.dispatchEvent(EventQueue.java:602)
        at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:275)
        at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:200)
        at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:190)
        at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:185)
        at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:177)
        at java.awt.EventDispatchThread.run(EventDispatchThread.java:138)

"AWT-Shutdown" prio=10 tid=0xad8a3c00 nid=0x19a5 in Object.wait() [0xad4dd000..0xad4ddfc0]
   java.lang.Thread.State: WAITING (on object monitor)
        at java.lang.Object.wait(Native Method)
        - waiting on <0xae2454f8> (a java.lang.Object)
        at java.lang.Object.wait(Object.java:502)
        at sun.awt.AWTAutoShutdown.run(AWTAutoShutdown.java:281)
        - locked <0xae2454f8> (a java.lang.Object)
        at java.lang.Thread.run(Thread.java:674)

"AWT-XAWT" daemon prio=10 tid=0xad894400 nid=0x19a4 waiting for monitor entry [0xad52e000..0xad52f040]
   java.lang.Thread.State: BLOCKED (on object monitor)
        at java.awt.Component.getName(Component.java:815)
        - waiting to lock <0xae1fabd8> (a java.awt.Dialog)
        at java.awt.Component.paramString(Component.java:7692)
        at java.awt.Container.paramString(Container.java:2852)
        at java.awt.Dialog.paramString(Dialog.java:1380)
        at java.awt.Component.toString(Component.java:7712)
        at java.lang.String.valueOf(String.java:2838)
        at java.lang.StringBuilder.append(StringBuilder.java:132)
        at sun.awt.X11.XDecoratedPeer.requestWindowFocus(XDecoratedPeer.java:1145)
        at sun.awt.X11.XDecoratedPeer.handleWmTakeFocus(XDecoratedPeer.java:1016)
        at sun.awt.X11.XDecoratedPeer.handleClientMessage(XDecoratedPeer.java:1005)
        at sun.awt.X11.XBaseWindow.dispatchEvent(XBaseWindow.java:1074)
        at sun.awt.X11.XBaseWindow.dispatchToWindow(XBaseWindow.java:1056)
        at sun.awt.X11.XToolkit.dispatchEvent(XToolkit.java:499)
        at sun.awt.X11.XToolkit.run(XToolkit.java:594)
        at sun.awt.X11.XToolkit.run(XToolkit.java:529)
        at java.lang.Thread.run(Thread.java:674)

"Java2D Disposer" daemon prio=10 tid=0xad873400 nid=0x19a3 in Object.wait() [0xad5e3000..0xad5e3ec0]
   java.lang.Thread.State: WAITING (on object monitor)
        at java.lang.Object.wait(Native Method)
        - waiting on <0xae1f5510> (a java.lang.ref.ReferenceQueue$Lock)
        at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:133)
        - locked <0xae1f5510> (a java.lang.ref.ReferenceQueue$Lock)
        at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:149)
        at sun.java2d.Disposer.run(Disposer.java:143)
        at java.lang.Thread.run(Thread.java:674)

"Low Memory Detector" daemon prio=10 tid=0x080b3c00 nid=0x19a1 runnable [0x00000000..0x00000000]
   java.lang.Thread.State: RUNNABLE

"CompilerThread0" daemon prio=10 tid=0x080b0c00 nid=0x19a0 waiting on condition [0x00000000..0xada868d8]
   java.lang.Thread.State: RUNNABLE

"Signal Dispatcher" daemon prio=10 tid=0x080af000 nid=0x199f waiting on condition [0x00000000..0x00000000]
   java.lang.Thread.State: RUNNABLE

"Finalizer" daemon prio=10 tid=0x0809e800 nid=0x199e in Object.wait() [0xadb6e000..0xadb6f140]
   java.lang.Thread.State: WAITING (on object monitor)
        at java.lang.Object.wait(Native Method)
        - waiting on <0xae1f56d8> (a java.lang.ref.ReferenceQueue$Lock)
        at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:133)
        - locked <0xae1f56d8> (a java.lang.ref.ReferenceQueue$Lock)
        at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:149)
        at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:177)

"Reference Handler" daemon prio=10 tid=0x08099c00 nid=0x199d in Object.wait() [0xadbbf000..0xadbbffc0]
   java.lang.Thread.State: WAITING (on object monitor)
        at java.lang.Object.wait(Native Method)
        - waiting on <0xae1f5760> (a java.lang.ref.Reference$Lock)
        at java.lang.Object.wait(Object.java:502)
        at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:133)
        - locked <0xae1f5760> (a java.lang.ref.Reference$Lock)

"main" prio=10 tid=0x0804fc00 nid=0x199b in Object.wait() [0xb7e23000..0xb7e2
   java.lang.Thread.State: WAITING (on object monitor)
        at java.lang.Object.wait(Native Method)
        - waiting on <0xae1fabd8> (a java.awt.Dialog)
        at java.lang.Object.wait(Object.java:502)
        at TemporaryLostComponentDeadlock.start(TemporaryLostComponentDeadloc
        - locked <0xae1fabd8> (a java.awt.Dialog)
        at TemporaryLostComponentDeadlock.main(TemporaryLostComponentDeadlock

"VM Thread" prio=10 tid=0x08096400 nid=0x199c runnable

"VM Periodic Task Thread" prio=10 tid=0x080b5800 nid=0x19a2 waiting on condit

JNI global references: 865

Heap
 def new generation   total 960K, used 363K [0xadcd0000, 0xaddd0000, 0xae1b00
  eden space 896K,  33% used [0xadcd0000, 0xadd1ae70, 0xaddb0000)
  from space 64K, 100% used [0xaddc0000, 0xaddd0000, 0xaddd0000)
  to   space 64K,   0% used [0xaddb0000, 0xaddb0000, 0xaddc0000)
 tenured generation   total 4096K, used 823K [0xae1b0000, 0xae5b0000, 0xb1cd0
   the space 4096K,  20% used [0xae1b0000, 0xae27de68, 0xae27e000, 0xae5b0000
 compacting perm gen  total 12288K, used 7841K [0xb1cd0000, 0xb28d0000, 0xb5c
   the space 12288K,  63% used [0xb1cd0000, 0xb24787b0, 0xb2478800, 0xb28d000
No shared spaces configured.

Comments
SUGGESTED FIX --- old/src/share/classes/java/awt/Component.java 2008-06-04 13:53:10.000000000 +0400 +++ new/src/share/classes/java/awt/Component.java 2008-06-04 13:53:10.000000000 +0400 @@ -635,11 +635,21 @@ */ private PropertyChangeSupport changeSupport; - // Note: this field is considered final, though readObject() prohibits - // initializing final fields. - private transient Object changeSupportLock = new Object(); - private Object getChangeSupportLock() { - return changeSupportLock; + /* + * In some cases using "this" as an object to synchronize by + * can lead to a deadlock if client code also uses synchronization + * by a component object. For every such situation revealed we should + * consider possibility of replacing "this" with the package private + * objectLock object introduced below. So far there're 2 issues known: + * - CR 6708322 (the getName/setName methods); + * - CR 6608764 (the PropertyChangeListener machinery). + * + * Note: this field is considered final, though readObject() prohibits + * initializing final fields. + */ + private transient Object objectLock = new Object(); + Object getObjectLock() { + return objectLock; } boolean isPacked = false; @@ -812,7 +822,7 @@ */ public String getName() { if (name == null && !nameExplicitlySet) { - synchronized(this) { + synchronized(getObjectLock()) { if (name == null && !nameExplicitlySet) name = constructComponentName(); } @@ -829,7 +839,7 @@ */ public void setName(String name) { String oldName; - synchronized(this) { + synchronized(getObjectLock()) { oldName = this.name; this.name = name; nameExplicitlySet = true; @@ -7838,7 +7848,7 @@ */ public void addPropertyChangeListener( PropertyChangeListener listener) { - synchronized (getChangeSupportLock()) { + synchronized (getObjectLock()) { if (listener == null) { return; } @@ -7864,7 +7874,7 @@ */ public void removePropertyChangeListener( PropertyChangeListener listener) { - synchronized (getChangeSupportLock()) { + synchronized (getObjectLock()) { if (listener == null || changeSupport == null) { return; } @@ -7887,7 +7897,7 @@ * @since 1.4 */ public PropertyChangeListener[] getPropertyChangeListeners() { - synchronized (getChangeSupportLock()) { + synchronized (getObjectLock()) { if (changeSupport == null) { return new PropertyChangeListener[0]; } @@ -7929,7 +7939,7 @@ public void addPropertyChangeListener( String propertyName, PropertyChangeListener listener) { - synchronized (getChangeSupportLock()) { + synchronized (getObjectLock()) { if (listener == null) { return; } @@ -7959,7 +7969,7 @@ public void removePropertyChangeListener( String propertyName, PropertyChangeListener listener) { - synchronized (getChangeSupportLock()) { + synchronized (getObjectLock()) { if (listener == null || changeSupport == null) { return; } @@ -7983,7 +7993,7 @@ */ public PropertyChangeListener[] getPropertyChangeListeners( String propertyName) { - synchronized (getChangeSupportLock()) { + synchronized (getObjectLock()) { if (changeSupport == null) { return new PropertyChangeListener[0]; } @@ -8004,7 +8014,7 @@ protected void firePropertyChange(String propertyName, Object oldValue, Object newValue) { PropertyChangeSupport changeSupport; - synchronized (getChangeSupportLock()) { + synchronized (getObjectLock()) { changeSupport = this.changeSupport; } if (changeSupport == null || @@ -8306,7 +8316,7 @@ private void readObject(ObjectInputStream s) throws ClassNotFoundException, IOException { - changeSupportLock = new Object(); + objectLock = new Object(); s.defaultReadObject();
04-06-2008

EVALUATION A decision has been taken to replace "this" lock in Component.getName/setName by some internal object.
29-05-2008

EVALUATION The exact deadlock scheme is as follows. [XAWT] -> AWTLock ->>> dialog (at Component.getName) [Thread-2] -> dialog -> waiting on AWTInvocationLock [EDT] -> AWTTreeLock -> InputMethodContext -> XInputMethod ->>> AWTLock Thus, we have 3 threads involved. XAWT holds AWTLock and can't take the dialog lock because Thread-2 (the second user thread) holds it. Thread-2 can't be awakened by EDT because EDT can't take AWTLock held by XAWT.
29-05-2008