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

C

Cherukan

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
 
E

Eric Sosman

Cherukan wrote On 05/24/07 14:45,:
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?

(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.
 
T

Tom Hawtin

Cherukan said:
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)

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

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
 
T

Tom Hawtin

Eric said:
Cherukan wrote On 05/24/07 14:45,:

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

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

Tom Hawtin
 
E

Eric Sosman

Tom Hawtin wrote On 05/24/07 17:27,:
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.
 
T

Tom Hawtin

Eric said:
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.
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.

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
 
E

Eric Sosman

Tom Hawtin wrote On 05/25/07 10:59,:
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.

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!
 
T

Tom Hawtin

Eric said:
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
 
C

Cherukan

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
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,539
Members
45,024
Latest member
ARDU_PROgrammER

Latest Threads

Top