12

(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: Why do people run Java GUI's on the Event Queue

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?

Community
  • 1
  • 1
NoozNooz42
  • 4,238
  • 6
  • 33
  • 53
  • 1
    An interesting side-note on a completely different matter: You don't have to do Math.abs(0) to "trick" the compiler to accept it. 0/0 is an ok expression and will also throw the exception. [read more...](http://stackoverflow.com/questions/2934063/is-1-0-a-legal-java-expression) – aioobe Jun 11 '10 at 07:28
  • @aioobe: he he, I know, I know, I've read that discussion... But if had written 0/0 or 1/0 then people would have asked it that thing was even compiling :) – NoozNooz42 Jun 11 '10 at 07:37
  • 1
    Looking at `EventDispatchThread.pumpOneEventForFilters`, in the current implementation "it's complicated". Obviously different implementations may vary. Before the EDT exiting when there were no realised windows, presumably exceptions were always caught. – Tom Hawtin - tackline Jun 11 '10 at 12:26

3 Answers3

5

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
  • 413,195
  • 112
  • 811
  • 826
  • @NoozNooz42, no, I think it's 6. Let me know if you find out that it has changed in java 7 :-) – aioobe Jun 11 '10 at 07:34
  • 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 Jun 11 '10 at 08:03
4

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
  • 203,806
  • 29
  • 246
  • 1,045
  • @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 Jun 11 '10 at 07:31
  • yeah. I'm on ubuntu using java 6. which system are you on trashgod? – aioobe Jun 11 '10 at 07:36
  • @NoozNooz42: While Mac OS X keeps the same ID, I see the incrementing you report on Ubuntu 10.04. – trashgod Jun 11 '10 at 07:39
  • @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 Jun 11 '10 at 07:46
  • @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 Jun 11 '10 at 07:46
  • @NoozNooz42: Yes, I see it, too. The button's highlighting remains set (gray) until the mouse exits the button. – trashgod Jun 11 '10 at 07:51
0

There is an default UncaughtExceptionHandler set on the Event Dispatch Thread, which prints the Exception to System.out and then continues in the Thread.

keuleJ
  • 3,418
  • 4
  • 30
  • 51