A common mistake when creating threads is to use the non-daemon variety that will cause the JVM to keep running even when System.exit() is called. The default constructor for Thread creates a “user” thread, which is often not the behaviour expected by the programmer. User threads are designed for important tasks which should not be arbitrarily stopped, like finishing a credit card transaction.
“The Java Virtual Machine exits when the only threads running are daemon threads”.
The following main( ) function will never finish.
public static void main(String[] args)
{
Thread worker = new Thread()
{
public void run()
{
for (;;) // ever
{
FileSystemManager.process();
try {Thread.sleep(10000L);} catch (Exception e) {}
}
}
};
worker.start();
DataManager.processUntilComplete();
}
The above code will never finish but not because of the for(;;)loop. A single line to setDaemon(true) added before the start( ) allows main( ) to exit when completed:
public static void main(String[] args)
{
Thread worker = new Thread()
{
public void run()
{
for (;;) // ever
{
FileSystemManager.process();
try {Thread.sleep(10000L);} catch (Exception e) {}
}
}
};
worker.setDaemon(true);
worker.start();
DataManager.processUntilComplete();
}
The useful Timer class has the same unexpected problem: by default it creates a user thread instead of a daemon thread.
// Repeatedly check for a new configuration file:
appTimer = new Timer();
appTimer.scheduleAtFixedRate
(
new TimerTask()
{
public void run()
{
try
{
checkRefreshConfiguration();
}
catch (Exception e)
{
logger.error("Invalid configuration", e);
}
}
}, RELOAD_DELAY_MSECS, RELOAD_PERIOD_MSECS
);
This timer thread had a worse effect, in that it prevented the web application from shutting down. The timer thread could be easily fixed, as below:
// Repeatedly check for a new configuration file:
appTimer = new Timer(true);
appTimer.scheduleAtFixedRate
(
new TimerTask()
{
public void run()
{
try
{
checkRefreshConfiguration();
}
catch (Exception e)
{
logger.error("Invalid configuration", e);
}
}
}, RELOAD_DELAY_MSECS, RELOAD_PERIOD_MSECS
);
Tip: Use only Daemon threads for general development. You need a pretty specific reason to use Non-Daemon threads.