January 14th, 2008

When DISPOSE_ON_CLOSE met WebStart

Today I am thrilled to have the first guest spot blogger on “Pushing Pixels”. Christopher Deckers, the developer of DJ project that brings rich native features to Swing applications, has graciously agreed to post a summary of his findings on using the DISPOSE_ON_CLOSE window close mode in WebStart environment. Note that a similar scenario was reported and fixed on another “rogue” VM thread.


After hours of coding, you finally release your wonderful Swing application. It is using Java 1.4 (or later), it was tested locally and it was terminating properly. You package it and release it as a Webstart application. Unfortunately, you are using setDefaultCloseOperation(DISPOSE_ON_CLOSE) on your JFrames. Soon, users complain that your application remains in memory after they hit the close button of the last frame.To track down this abnormal behavior, you read the AWT threading rules again, detailed in the following file from the javadoc:

“Prior to 1.4, the helper threads were never terminated.Starting with 1.4, the behavior has changed as a result of the fix for 4030718. With the current implementation, AWT terminates all its helper threads allowing the application to exit cleanly when the following three conditions are true:

* There are no displayable AWT or Swing components.
* There are no native events in the native event queue.
* There are no AWT events in java EventQueues.”

It sounds like you are respecting the rules, so something somewhere is misbehaving. The culprit seems to be Webstart.

The JVM should exit, which means there is a non-daemon thread alive in the system:

  1. The non-daemon thread is a Webstart-related system thread.
  2. The non-daemon thread is the event queue.

Creating a simple test case (an empty JFrame using DISPOSE_ON_CLOSE), we add a timer to dump all the threads a few seconds after we actually close the application.
Comparing a local run and a Webstart run, we see several additional threads in the latter case:

Javaws Secure Thread (non-daemon)
traceMsgQueueThread (daemon)
Image Fetcher 0 (daemon)
CacheCleanUpThread (daemon)
AWT-EventQueue-1 (non-daemon)
TimerQueue (daemon)
TimerQueue (daemon)

Surprisingly, we can see two UI threads (AWT-EventQueue-1 in addition to AWT-EventQueue-0) and a special Webstart thread named “Javaws Secure Thread“.

A quick test shows that if we forcibly kill the “Javaws Secure Thread” (using the not-so-recommended call to Thread.stop()), then closing the application succeeds.

This behavior leads to two conclusions: this Webstart thread is a non-daemon thread so the JVM cannot exit, and it also seems to post new events to the UI thread that restarts it.

Time to hunt for the code of the “Javaws Secure Thread“!

A quick search in jre\lib\javaws.jar and we can find its declaration: a class named SecureThread, nested in the com.sun.javaws.ui.JavawsSysRun class (the code can be found in deploy\src\javaws\share\classes\com\sun\javaws\ui folder of the JDK source distribution).

The code after simplification is roughly equivalent to the following:

class SecureThread extends Thread {
   public void run() {
      while(true) {
         doWork();
      }
   }
   public void doWork() {
      SwingUtilities.invokeLater(new Runnable() {
         public void run() {
            // stuff
         }
      }
      // other stuff
   }
}

All seems confirmed: Webstart does create a non-daemon thread, which continuously posts events to the UI thread.

The solution? Well, like back in the 1.3 days, use EXIT_ON_CLOSE on the main frame (if any) until this eventually gets fixed in webstart.