<AWT Dev> Endless loop in EventDispatchThread - proposed solution
Artem Ananiev
artem.ananiev at oracle.com
Mon Aug 22 08:13:14 PDT 2011
Hi, Clemens,
thanks for digging into that. AWT shutdown code is far from perfect, but
this is not a reason for not fixing bugs there :)
See my comments below.
On 8/21/2011 3:25 PM, Clemens Eisserer wrote:
> Hi,
>
> On our caciocavallo-web demo server I sometimes experience endless
> spinning in an EventDispatchThread (in run()) which should have been
> shut down long ago by AppContext.dispose() - causing our server to
> consume 100% cpu.
>
> I tried to anylze the situation using a remote debugger, this is what
> I've found:
>
> The thread is interrupted, therefor no events are dispatched anymore by
> pumpEventsForFilter:
>
> while (doDispatch && cond.evaluate()) {
> if (isInterrupted() || !pumpOneEventForFilters(id)) {
> doDispatch = false;
> }
> }
>
>
> however, detaching the thread from the EventQueue fails, because there
> are still events left for dispatching,
> which in turn won't be dispatched, because the thread is interrupted.
>
> 1.) A fix would be to check for isInterruped also in the thread's run loop:
>
> public void run() {
> while (true) {
> try {
> pumpEvents(new Conditional() {
> public boolean evaluate() {
> return true;
> }
> });
> } finally {
> EventQueue eq = getEventQueue();
> if (eq.detachDispatchThread(this) ||
> threadDeathCaught || isInterrupted()) {
> break;
> }
> }
> }
> }
>
>
> What do you think about the proposed solutions?
I may be a bit naive: to me, if a thread is interrupted, it should
gracefully go away (and this is what AppContext.dispose() relies on), so
in general I like the idea of handling isInterrupted() in
EventDispatchThread.
I tried to slightly change your patch. The problem with checking for
isInterrupted() in EDT.run(), as well as for threadDeathCaught, is that
the thread will never be marked free in AWTAutoShutdown. To fix that, we
should make EQ.detachDispatchThread() unconditional, so it always
detaches the thread, but this would lead to the very next postEvent()
will initialize a new dispatch thread...
> 2.) A big mystery for me was, why the thread hasn't been killed by
> Thread.stop(), called by AppContext.dispose() - and why the
> "threadDeathCaught"-variable was still false (as this would have caused
> the thread to exit anyway).
> The reason was, ThreadDeath is swollowed by the
> IllegalMonitorStateException caused by Thread.stop():
>
> Basically this is what is going on, when waiting for new events:
>
> pushPopLock.lock();
> try {
> cond.await(); //Throws ThreadDeath
> }finally {
> pushPopLock.unlock(); //Throws IllegalMonitorStateException,
> "swollows" ThreadDeath
> }
>
> So ThreadDeath is never catched.
>
> This bug has been introduced when converting to java.util.concurrent, as
> java monitors don't throw an exception in this situation.
> My proposal for this bug would be to do away with the
> threadDeathCaught-variable completly, as the isInterrupted()-check
> proposed in 1.) will stop the thread anyway.
What if somebody calls EDT.stop() directly, without preceding
interrupt()? I understand this is not a typical scenario, and we
probably shouldn't support it, but we should at least not hang.
> Thanks, Clemens
Thanks,
Artem
More information about the awt-dev
mailing list