views:

97

answers:

2

(the example code below is self-contained and runnable, you can try it, it won't crash your system :)

Tom Hawtin commented on the question here: http://stackoverflow.com/questions/3018165

that:

It's unlikely that the EDT would crash. Unchecked exceptions thrown in EDT dispatch are caught, dumped and the thread goes on.

Can someone explain me what is going on here (every time you click on the "throw an unchecked exception" button, a divide by zero is performed, on purpose):

import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

public class CrashEDT extends JFrame {

    public static void main(String[] args) {
        final CrashEDT frame = new CrashEDT();
        frame.addWindowListener(new WindowAdapter() {
            public void windowClosing( WindowEvent e) {
                System.exit(0);
            }
        });
        final JButton jb = new JButton( "throw an unchecked exception" );
        jb.addActionListener( new ActionListener() {
            public void actionPerformed( ActionEvent e ) {
                System.out.println( "Thread ID:" + Thread.currentThread().getId() );
                System.out.println( 0 / Math.abs(0) );
            }
        } );
        frame.add( jb );
        frame.setSize(300, 150);
        frame.setVisible(true);
    }

}

I get the following message (which is what I'd expect):

Exception in thread "AWT-EventQueue-0" java.lang.ArithmeticException: / by zero

and to me this is an unchecked exception right?

You can see that the thread ID is getting incremented every time you trigger the crash.

So is the EDT automatically restarted every time an unchecked exception is thrown or are unchecked exceptions "caught, dumped and the thread goes on" like Tom Hawtin commented?

What is going on here?

+2  A: 

Interesting question. I would have thought that the exceptions were caught and that the thread went on, but after some research I'm not so sure.

I extended your program with a

Set<Thread> seenAwtThreads = new HashSet<Thread>();

in which I collected all "seen" awt threads, and the size of the set increases each time I click the "throw exception"-button, which seems to suggest that a new thread is initialized in case of an exception.

Finally I found this comment in the run implementation of EventDispatchThread:

/*
 * Event dispatch thread dies in case of an uncaught exception. 
 * A new event dispatch thread for this queue will be started
 * only if a new event is posted to it. In case if no more
 * events are posted after this thread died all events that 
 * currently are in the queue will never be dispatched.
 */

The implementation of the complete run method looks like:

public void run() {
    try {
        pumpEvents(new Conditional() {
            public boolean evaluate() {
                return true;
            }
        });     
    } finally {
        /*
         * This synchronized block is to secure that the event dispatch 
         * thread won't die in the middle of posting a new event to the
         * associated event queue. It is important because we notify
         * that the event dispatch thread is busy after posting a new event
         * to its queue, so the EventQueue.dispatchThread reference must
         * be valid at that point.
         */
        synchronized (theQueue) {
            if (theQueue.getDispatchThread() == this) {
                theQueue.detachDispatchThread();
            }
            /*
             * Event dispatch thread dies in case of an uncaught exception. 
             * A new event dispatch thread for this queue will be started
             * only if a new event is posted to it. In case if no more
             * events are posted after this thread died all events that 
             * currently are in the queue will never be dispatched.
             */
            /*
             * Fix for 4648733. Check both the associated java event
             * queue and the PostEventQueue.
             */
            if (theQueue.peekEvent() != null || 
                !SunToolkit.isPostEventQueueEmpty()) { 
                theQueue.initDispatchThread();
            }
            AWTAutoShutdown.getInstance().notifyThreadFree(this);
        }
    }
}
aioobe
@aioobe: +1, this is interesting. That code is from Java 7?
NoozNooz42
@NoozNooz42, no, I think it's 6. Let me know if you find out that it has changed in java 7 :-)
aioobe
@aioobe: Sorry for the delayed reply. I used Java 1.6 on both Mac OS X 10.5.8 and Ubuntu 10.04. The Mac source is identical to that shown by you.
trashgod
+3  A: 

For reference, "The particular behavior of this machinery is implementation-dependent." For example, the thread ID remains unchanged on my platform. The net effect, discussed in AWT Threading Issues, is that "the JVM will not exit while there is at least one displayable component."

trashgod
@trashgod: I only tried it on a Debian Linux system so far :) +1, and that http://java.sun.com/javase/6/docs/api/java/awt/doc-files/AWTThreadIssues.html link is excellent stuff!
NoozNooz42
yeah. I'm on ubuntu using java 6. which system are you on trashgod?
aioobe
@NoozNooz42: While Mac OS X keeps the same ID, I see the incrementing you report on Ubuntu 10.04.
trashgod
@trashgod: yup, just tried on both OS X 10.4 / Tiger / Java 1.5 and OS X 10.6 / Snow Leopard / Java 1.6 and on both the ID stays the same. I *think* on OS X after the button release the button is not correctly redrawn (after the crash, it's like if the mouse release event was lost) while on Linux the button release is correctly taken into account (not sure that said).
NoozNooz42
@NoozNooz42: I used Java 1.6 on both Mac OS X 10.5.8 and Ubuntu 10.04. Th eMac Source is identical to that shown by @aioobe.
trashgod
@NoozNooz42: Yes, I see it, too. The button's highlighting remains set (gray) until the mouse exits the button.
trashgod