<AWT Dev> Endless loop in EventDispatchThread - proposed solution
David Holmes
David.Holmes at oracle.com
Sun Aug 21 22:06:10 PDT 2011
Hi Clemens,
On 21/08/2011 9:25 PM, Clemens Eisserer wrote:
> 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?
It seems to me that when the app context is being shutdown in this manner
that part of that should be to purge/clear the event queue. To me that would
be a more appropriate fix for this non-terminating situation.
>
> 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.
Right. The ThreadDeath gets seen while trying to acquire the Lock to return
from await() and so the lock is not reacquired and so the subsequent
unlock() throws IMSE. There's an open bug on this (6627356), against
Condition.await, but like anything to do with async exceptions there are no
easy solutions. I'd prefer if AppContext could stop using a method that's
been deprecated for a decade (and which I'd love to physically remove in
Java 8).
BTW the interrupt() should really be causing the await() to complete, but
there must be contention on the Lock causing the stop() to be issued before
the lock is acquired. Maybe that contention could be removed to allow the
interrupt() to do all the work?
> 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.
Seems to me that there should be a simple variable that the run() method can
check which gets set when the thread is expected to terminate. That way it
doesn't matter whether it gets hit by the interrupt() or the stop(), it will
terminate based on the flag.
But any changes to this code need deep scrutiny - I know many eyes have
looked at it over the years. And there's no doubt a fair amount of
historical baggage as well.
David
> Thanks, Clemens
>
>
>
>
More information about the awt-dev
mailing list