Timer death

Ariel Weisberg ariel at weisberg.ws
Fri Jul 9 17:44:20 UTC 2010


Hi Pawel,

You have pointed out a number of known issues with Timer. The class is
not deprecated, but there is a much improved version available in
java.util.concurrent.ScheduledThreadPoolExecutor
(http://download.oracle.com/docs/cd/E17409_01/javase/6/docs/api/). That
too has its owns quirks when tasks leak Exceptions, but it is still an
improvement. You should read the STPE specific javadoc for the various
execute/submit/schedule methods carefully and make sure to extend STPE
in order to implement
java.util.concurrent.ThreadPoolExecutor.afterExecute() (and see the
javadoc for that method for some more magic) in order to make sure you
can catch and handle exceptions thrown by tasks.

It's interesting that the javadoc for Timer doesn't mention STPE. Might
be a worthwhile enhancement.

Hope this helps,
Ariel Weisberg

On Fri, 09 Jul 2010 10:32 -0700, "Pawel Veselov"
<pawel.veselov at gmail.com> wrote:
> Greetings,
> 
> After debugging an issue in one of my projects, I've realized that the
> problem was that a timer task simply died because VM was out of
> memory.
> The fact that I catch any Throwable around the code that threw the OOM
> error didn't particularly help. The error was logged, but the timer
> thread still died.
> Well, may be it didn't die at this point, I do see the exception
> handling code executed (it logged something else from the catch{}
> block as well), and I really hope (don't believe) that a thread would
> die when normal exception handling was executed and the exception
> wasn't re-thrown upstream.
> 
> But, I'm not here to ramble about particulates about my specific
> situations. When I started thinking about how do I detect this
> somehow, I also realized that it's not normally possible to determine
> if any specific timer is alive or not. I see two ways to determine
> that:
> 
> a) Schedule a single empty task on a timer. If you get back an
> IllegalStateException, then the timer thread is gone (the code
> suggests if the thread leaves the main loop for any reason, any
> scheduling will cause IllegalStateException).
> b) When the timer is created, schedule a single task, and determine
> the timer thread during the task execution (current thread), and then
> check whether the thread is running or not.
> 
> Now, both of those are hacky, "a" schedules a task for no reason, and
> "b" will stop working if timer implementation becomes capable of
> scheduling tasks on multiple threads for whatever load-balancing
> reasons.
> 
> I would suggest adding a method to either retrieve a timer thread
> (sort of bad, because this will make the timer implementation to
> always use a single thread), or simply a method that tells whether the
> timer is alive or not (whether this would now translate into whether
> the thread is alive or not), so the program can attempt to recover (or
> take any other action, like shooting itself) if the timer stopped
> working.
> 
> My overall issue with this (I know, kind of late to realize this now),
> is that it's really hard to recover from OOMs, or even detect that
> they are happening, and all of the sudden your application threads
> start to simply disappear, and you need yet another thread that would
> go check they are alive and take some action (and who is to say that
> thread won't die as well, and you won't notice that either).
> 
> java.lang.OutOfMemoryError: Java heap space
> 	at sun.reflect.GeneratedConstructorAccessor5.newInstance(Unknown Source)
> 	at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
> 	at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
> 	at com.mysql.jdbc.Util.handleNewInstance(Util.java:409)
> 	at com.mysql.jdbc.ResultSetImpl.getInstance(ResultSetImpl.java:382)
> 	at com.mysql.jdbc.MysqlIO.buildResultSetWithRows(MysqlIO.java:2604)
> 	at com.mysql.jdbc.MysqlIO.getResultSet(MysqlIO.java:487)
> 	at com.mysql.jdbc.MysqlIO.readResultsForQueryOrUpdate(MysqlIO.java:2582)
> 	at com.mysql.jdbc.MysqlIO.readAllResults(MysqlIO.java:1758)
> 	at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2172)
> 	at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2690)
> 	at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2619)
> 	at com.mysql.jdbc.StatementImpl.executeQuery(StatementImpl.java:1465)
>         <classified>
> 	at java.util.TimerThread.mainLoop(Timer.java:512)
> 	at java.util.TimerThread.run(Timer.java:462)
> 
> 
> Thanks,
>   Pawel.
> 



More information about the core-libs-dev mailing list