Home | Contact Us | FAQ | Search & Site Map | Link to Us
Sign In | Join | Other 45 Sites in Network
HomeAnnouncementsWhite Papers
Discussion GroupsFirst AidDatabasesJavaBeansGUIJava 3DVirtual MachineCORBASecurityToolsGeneral
Java DirectoryOpen Source ProjectsSample Book ChaptersUser GroupsWeb Resources
Related Topics
Databases.NETMore Topics ...

Java Forum / General / May 2007

Tip: Looking for answers? Try searching our database.

java.lang.IllegalStateException: Deadlock risk: AWT tree lock acquired on a showing component..

Thread view: 
Cherukan - 24 May 2007 19:45 GMT
Hi

I get this error when trying to popup a Swing dialog from a long-
running background thread.

java.lang.IllegalStateException: Deadlock risk: AWT tree lock acquired
on a
showing component when not on the event dispatch thread.  (NOTE: do
*not* use
invokeAndWait to fix this assertion failure; that will increase the
chance of
actual deadlock.)
Thread name: task1-1438375310
      at
java.awt.Component.assertThreadPolicyCompliance(Component.java:8566)
      at java.awt.Component.getTreeLock(Component.java:871)
      at java.awt.Component.getLocationOnScreen(Component.java:1651)

I realize this is happening because the current thread is not the
event thread.

But the background thread must get this input from the user to
proceed. Also the input
depends on the processing the thread has done upto this point, so it
cannot be
obtained before the thread has started. After the swing dialog has
closed, the thread
needs to resume its processing picking up where it left off.

As the message says, I cant use invokeAndWait.

Whats the 'safe' approach in such a case?

Thanks for your answers.

Cherukan
Eric Sosman - 24 May 2007 22:07 GMT
Cherukan wrote On 05/24/07 14:45,:
> Hi
>
[quoted text clipped - 28 lines]
>
> Whats the 'safe' approach in such a case?

   (Warning: not tested.)  The long-running worker
thread uses invokeLater() to cause the EDT to display
the dialog, and then puts itself to sleep by calling
wait() on some convenient object.  When the dialog
gets the desired response, it puts the input into the
aforementioned convenient object and calls notify()
to awaken the sleeping worker thread.

Signature

Eric.Sosman@sun.com

Tom Hawtin - 24 May 2007 22:27 GMT
> Cherukan wrote On 05/24/07 14:45,:
>>
[quoted text clipped - 9 lines]
> aforementioned convenient object and calls notify()
> to awaken the sleeping worker thread.

That's effectively what invokeAndWait does. Rolling your own version
wont help.

Tom Hawtin
Eric Sosman - 24 May 2007 22:55 GMT
Tom Hawtin wrote On 05/24/07 17:27,:

>>Cherukan wrote On 05/24/07 14:45,:
>>
[quoted text clipped - 12 lines]
> That's effectively what invokeAndWait does. Rolling your own version
> wont help.

   You could be right, but I'd be surprised if my
suggestion would risk deadlock.  (Perhaps I should
have said that by "some convenient object" it was to
be understood that the object wasn't a GUIgadget,
but a plain old StringBuilder or ArrayList or some
such "free-standing" sort of object.)

   I'll be the first to admit that I find the code
for EventQueue.invokeAndWait() to be impenetrable.
For example, the call to lock.wait() looks like an
obvious beginner bug (Where's the state test?  What
about spurious wakeups?) -- but if it were a bug it
would surely have surfaced by now, so there must be
a good deal more going on than meets my eye.

Signature

Eric.Sosman@sun.com

Tom Hawtin - 25 May 2007 15:59 GMT
>     You could be right, but I'd be surprised if my
> suggestion would risk deadlock.  (Perhaps I should
> have said that by "some convenient object" it was to
> be understood that the object wasn't a GUIgadget,
> but a plain old StringBuilder or ArrayList or some
> such "free-standing" sort of object.)

The problem is invokeAndWait works like a lock, although Sun's JVM wont
detect it as deadlocking in stack traces. If you hold two 'random' locks
at the same time, you are asking for trouble.

The Swing tutorial seems to have been dumbed down not to mention the
problem (nice). I wrote a weblog entry mentioning the problem a while back:

http://www.jroller.com/page/tackline?entry=detecting_invokeandwait_abuse

>     I'll be the first to admit that I find the code
> for EventQueue.invokeAndWait() to be impenetrable.
[quoted text clipped - 3 lines]
> would surely have surfaced by now, so there must be
> a good deal more going on than meets my eye.

Sun's JVM doesn't actually allow spurious wakeups. The bug for
invokeAndWait is:

http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4974934

Tom Hawtin
Eric Sosman - 25 May 2007 16:40 GMT
Tom Hawtin wrote On 05/25/07 10:59,:

>>    You could be right, but I'd be surprised if my
>>suggestion would risk deadlock.  (Perhaps I should
[quoted text clipped - 6 lines]
> detect it as deadlocking in stack traces. If you hold two 'random' locks
> at the same time, you are asking for trouble.

   May I abuse your patience a little longer?  I'm
still not seeing the problem, and if one does in fact
exist I'd like to understand it at a deeper level than
"Don't Do That."

   My suggestion is (pseudocode)

    final Thing thing = new Thing();
    synchronized(thing) {
       SwingUtilities.invokeLater(new Runnable() {
           public void run() {
               // display dialog, get user input
               synchronized(thing) {
                   thing.putData(userInput);
                   thing.notify();
               }
           }
       });
       while (! thing.hasData())
           thing.wait();
    }
    Data userInput = thing.getData();
    // merrily we roll along

   It seems to me -- here's where I need help -- that
there are two different threads interested in the lock
on thing: the launching thread shown above, and the EDT.
If invokeLater() returns without waiting for the EDT to
do something, then the launching thread will proceed to
the thing.wait() call, which releases the lock.  This
will allow the EDT to acquire thing's lock in the Runnable
(it may or may not have already been waiting to do so).
Once it gets the lock, it runs through its synchronized
block and releases it again.  The launching thread can
then awaken from thing.wait(), re-acqure the lock, and
test the state of thing.  It looks like both threads
are certain to be able to make progress, so where's the
deadlock risk?

   Is there a situation in which invokeLater() waits
for the EDT to run the Runnable before returning?  That
would be a deadlock for certain, not just in prospect!

Signature

Eric.Sosman@sun.com

Tom Hawtin - 25 May 2007 19:30 GMT
>     My suggestion is (pseudocode)

That's essentially what a safe implementation of invokeAndWait would do
(only it'd needs to propagate any exception across threads so as not to
hang).

> test the state of thing.  It looks like both threads
> are certain to be able to make progress, so where's the
> deadlock risk?

It's only a problem if there is another lock involved. The reason to be
on the EDT is because of Swing, which means AWT, which means locks. The
thread started with an unknown implementation of AWT (not Sun's AFAICS)
implementation of Component.getTreeLock. (The actual use of tree lock is
poorly documented.)

There is a risk of a thread acquiring the tree lock and then attempting
to wait for the EDT. That could deadlock (although it would not be
detected in stack dumps).

The second lock need not be the AWT tree lock. It could be any other
lock, or even the EDT waiting for the other thread.

So, to stay away from danger, go event based.

Tom Hawtin
Tom Hawtin - 24 May 2007 22:11 GMT
> I get this error when trying to popup a Swing dialog from a long-
> running background thread.
[quoted text clipped - 11 lines]
>        at java.awt.Component.getTreeLock(Component.java:871)
>        at java.awt.Component.getLocationOnScreen(Component.java:1651)

Which version (and vendor) of Java is this?

> I realize this is happening because the current thread is not the
> event thread.

Yes, don't use Swing off the EDT.

> But the background thread must get this input from the user to
> proceed. Also the input
[quoted text clipped - 5 lines]
>
> As the message says, I cant use invokeAndWait.

Certainly invokeAndWait can cause deadlocks. However, invokeAndWait can
be used safely.

Assuming the EDT never has to wait for your thread, just use
invokeAndWait or equivalent.

If the EDT may need to wait for your thread, use event based techniques.
Give you thread an event dispatch loop that pulls events off a
(blocking) queue and dispatches them. Rearrange your code so that it
uses invokeLater, and the code after showing the modal (I assume) dialog
into another event that can be queued on the EDT.

However, modal user interfaces suck (IMO).

Tom Hawtin
Cherukan - 25 May 2007 20:12 GMT
Thanks for all the answers...

> Certainly invokeAndWait can cause deadlocks. However, invokeAndWait can
> be used safely.
>
> Assuming the EDT never has to wait for your thread, just use
> invokeAndWait or equivalent.
Therein lies the problem, I can assume, but cant be sure that the
thread
that needs to invokeAndWait does not hold any locks, especially in my
case
where the thread is not initiated by the class that needs to popup the
dialog, my class is a plug-in in a wider framework.
Your example of detecting monitors in the event dispatch thread is
quite
neat. I can definitely assert it, the only slight concern is that it
might
be a sledge hammer, since not all monitors are bad I suppose.

> If the EDT may need to wait for your thread, use event based techniques.
> Give you thread an event dispatch loop that pulls events off a
> (blocking) queue and dispatches them. Rearrange your code so that it
> uses invokeLater, and the code after showing the modal (I assume) dialog
> into another event that can be queued on the EDT.

I thought of this approach, but couple of reasons to decide against
it..
- since my class is a plugin in a framework, this would require quite
a bit of rearranging at the framework level since the thread does a
lot of
tasks that requires objects to keep their state in between. It would
require a
lot of closure-like constructs to carry these objects between
different threads.
- running the tasks on the EDT, even if queued, defeats the purpose of
the background thread, which is to free the EDT and keep the gui as
responsive as possible.

Thanks much for the suggestions.

Cherukan


Free Magazines

Get these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...

Oracle MagazineNetwork ComputingComputer WorldBio-IT WorldeWeekInformation WeekInfosecurity
 
Sign In
Join
My Latest Posts
My Monitored Threads
My Blog
My Photo Gallery
My Profile
My Homepage

Start New Thread
Enable EMail Alerts
Rate this Thread



©2008 Advenet LLC   Privacy Policy - Terms of Use
This website includes both content owned or controlled by Advenet as well as content owned or controlled by third parties.