JDK-6792511 : main exists before javax.swing.Timer's start() can start
  • Type: Enhancement
  • Component: client-libs
  • Sub-Component: java.awt
  • Affected Version: 6
  • Priority: P4
  • Status: Open
  • Resolution: Unresolved
  • OS: windows_vista
  • CPU: x86
  • Submitted: 2009-01-12
  • Updated: 2011-04-28
Related Reports
Relates :  
Relates :  
Description
FULL PRODUCT VERSION :
java version "1.6.0_07"
Java(TM) SE Runtime Environment (build 1.6.0_07-b06)
Java HotSpot(TM) Client VM (build 10.0-b23, mixed mode, sharing)

ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows [Version 6.0.6001]

EXTRA RELEVANT SYSTEM CONFIGURATION :
Nothing in particular: dual core,

A DESCRIPTION OF THE PROBLEM :
In a little demo program, main creates a javax.swing.Timer object.  After starting it with a start(), the main exits.  The Timer doesn't start, no actionPerformed occurs.

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
create an javax.swing.Timer object, with anonymous inner class actionPreformed.
Execute the object's start() method.
Exit the main.
(see supplied code)

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Expect the timer to start running and continue to run.
ACTUAL -
Main exits, timer does not execute.

ERROR MESSAGES/STACK TRACES THAT OCCUR :
no output

REPRODUCIBILITY :
This bug can be reproduced always.

---------- BEGIN SOURCE ----------
import javax.swing.*;
import java.awt.event.*;
// Shows bug in swing Timer, by Michael Floeser.
public class TimerSwingTest
{
	private static int swingCount = 0;
	public static void main(String [] args)
	{	// 1000 time here, <=999 it keeps going with Thread.sleep, otherwise exits.
		javax.swing.Timer swingTime = new javax.swing.Timer( 1000,  new ActionListener() {
			public void actionPerformed(ActionEvent ae)
			{
				System.out.println("Swing time count = " + ++swingCount );
			}
		} );
		
		swingTime.start();
		
		// sleep below <1000, (eg: 500), or removed, thread doesn't run
		//        =1000-IllegalStateException
		//        >1000-(eg: 2000) runs, but frequently exists ~1 minute or less
//		try{ Thread.sleep(2000); }
//		catch(Exception e){System.out.println("Sleep exception");}
	}
}
---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
Adding the Thread.sleep(2000) has it run, but frequently exists after about a minute. Sometimes it exists between 20 and 80 seconds, sometimes it goes longer.

Comments
EVALUATION Described behavior - when application exits before Swing timer is started - is correct. Here is what's going then: 1. Swing timer is created. 2. Separate thread for swing timer is started. It will notify attached actionListeners when the timeout is passed by posting an instance of InvocationEvent to EDT. 3. Main thread exits. 4. At this moment there is no non-daemon threads running in JVM. Application is terminated. There may be some variations - sometimes application doesn't exit immediately, but after sime period of running: 4. For some reason EDT (which is non-daemon) is started. JVM doesn't exit until this thread is terminated. 5. AWT has implementation of so called auto shutdown: when there are no peers and native/Java events pending, it terminates EDT to allow JVM exit. However, EDT is not terminated immediately, but after a second of idleness (with no peers and events exist). If Swing timer posts a new event during this one second timeout, AWT auto shutdown is postponed and reactivated after this event is processed. 6. At this moment there is a thread race between Swing timer and AWT auto shutdown. It leads to auto shutdown to "win" at some certain moment and JVM termination.
13-01-2009

EVALUATION Still, I'm not closing this CR as not a defect, because from developers' point of view this inconsistency - thread race highly depends on Swing timer timeout - looks strange. One of the ways to fix (workaround?) the problem is to mark all the Swing timer events as "weak", so they wouldn't affect AWT auto shutdown and wouldn't prevent JVM from exit. This looks like a RFE rather than a defect.
13-01-2009