Handling the throwable "ThreadDeath"

R

RVic

This question may be entirely JBoss - specific, but perhaps not, hence
I am posting here. In an application running in JBoss 5.1 GA, I am
getting a certain condition (I am required in this project to use the
JBoss Threadpool, a rather opaque creature, rather than roll my own):

WARN [RunnableTaskWrapper] Unhandled throwable for runnable:
com.sbase.ts.listener.ConnHandle@19d477f3
java.lang.ThreadDeath
at java.lang.Thread.stop(Thread.java:732)
at org.jboss.util.threadpool.RunnableTaskWrapper.stopTask
(RunnableTaskWrapper.java:122)
at org.jboss.util.threadpool.BasicThreadPool$TimeoutInfo.stopTask
(BasicThreadPool.java:631)
at org.jboss.util.threadpool.BasicThreadPool$TimeoutMonitor.run
(BasicThreadPool.java:694)
at java.lang.Thread.run(Thread.java:636)

My question is how do I handle this? Can I just let it go (the system
seems to run fine afterwards -- but maybe I have thread leakage?). How
do you handle this "ThreadDeath" throwable in a try-catch block, and
what do you do with it afterwards? -RVince
 
M

markspace

RVic said:
My question is how do I handle this?

I believe this means somebody (else) called Thread.stop() on the thread.
I think you should handle this by finding the code that calls stop()
and determining if it's correct or needs to be improved.

That brings up a question for me: Let's say you have a big old code base
like JBoss plus some frameworks. Is there any way to grep the byte
codes for method calls? Would you use javap for this and literally grep
the results or is there a better way?
 
L

Lothar Kimmeringer

Eric said:
But the "real" cure is to stop using stop().

I'm not using stop() but I always do something like this if I'm
forced to execute code that is depending on an external library
or is executing external code:

try{
[execute the "untrusted" code
}
catch(Throwable t){
logError("something bad happened", t);
if (t instanceof ThreadDeath){
throw (ThreadDeath) t;
}
}

Alternatively you can catch ThreadDeath before catching Throwable
but above solution avoids double code for logging.

But it's bad style as well to catch Throwable but to keep your
server running even e.g. with a missing library leading to a
NoClassDefFoundError or similar things you can't come around that.


Regards, Lothar
--
Lothar Kimmeringer E-Mail: (e-mail address removed)
PGP-encrypted mails preferred (Key-ID: 0x8BC3CD81)

Always remember: The answer is forty-two, there can only be wrong
questions!
 
G

Gerald Murdock

markspace said:
I believe this means somebody (else) called Thread.stop() on the thread.
I think you should handle this by finding the code that calls stop()
and determining if it's correct or needs to be improved.

Since Thread.stop() is deprecated, I'd say it needs to be improved.
 
M

markspace

Gerald said:
Since Thread.stop() is deprecated, I'd say it needs to be improved.


Well, if it's being called by a library or JBoss itself, code changes
may not be possible. I think in those cases I'd like to understand why
it's being called (normal exit for that library? did my thread ignore
an interrupt for too long?) and understand what could, and should, be
done about it.

It's deprecated, sure, but that doesn't mean blindly avoided at any
cost. It just means to be extra careful when calling that method,
because there may be special issues or side effects.
 
G

Gerald Murdock

markspace said:
Well, if it's being called by a library or JBoss itself, code changes
may not be possible. I think in those cases I'd like to understand why
it's being called (normal exit for that library? did my thread ignore
an interrupt for too long?) and understand what could, and should, be
done about it.

It's deprecated, sure, but that doesn't mean blindly avoided at any
cost. It just means to be extra careful when calling that method,
because there may be special issues or side effects.

No, it means "Sun has built a better way to do the same jobs, but has
preserved the old and potentially evil way in the interests of backwards
compatibility". In this case, the new-and-better-way is to use
Thread.interrupt() and InterruptedException.
 
M

markspace

No, it means "Sun has built a better way to do the same jobs, but has
preserved the old and potentially evil way in the interests of backwards
compatibility". In this case, the new-and-better-way is to use
Thread.interrupt() and InterruptedException.


Right, preserved for legacy code, so that code which is working now is
not required to be changed. If JBoss is calling stop(), and provides no
alternative, how is the OP going to "improve" his code?
 
R

Richard Maher

Gerald Murdock said:
No, it means "Sun has built a better way to do the same jobs, but has
preserved the old and potentially evil way in the interests of backwards
compatibility". In this case, the new-and-better-way is to use
Thread.interrupt() and InterruptedException.

Then why doesn't "SUN" use the better way for stopping Applet threads?

Regards Richard Maher
 
M

markspace

Richard said:
Then why doesn't "SUN" use the better way for stopping Applet threads?


Sun uses all sorts of deprecated methods and classes in their API.
Their code is rife with uses of HashTable and StringBuffer, for example.
I think "deprecated" is taken too strongly by some people. It's only
if the code is being redesigned and refactored that you should eliminate
deprecated methods, imo. Otherwise "if it ain't broke don't fix it" is
the best practice.

Note of course this implies that your use of a deprecated method or
classes really is not broken. If it is broke, then it must be fixed.
 
G

Gerald Murdock

markspace said:
Sun uses all sorts of deprecated methods and classes in their API. Their
code is rife with uses of HashTable and StringBuffer, for example. I
think "deprecated" is taken too strongly by some people. It's only if
the code is being redesigned and refactored that you should eliminate
deprecated methods, imo. Otherwise "if it ain't broke don't fix it" is
the best practice.

Note of course this implies that your use of a deprecated method or
classes really is not broken. If it is broke, then it must be fixed.

Which seems to me to be missing the point: apparently it IS broke, to
the point that someone is contemplating catching ThreadDeath and doing
other equally-dubious things to work around issues created by the use of
Thread.stop().
 
M

markspace

Gerald said:
Which seems to me to be missing the point: apparently it IS broke, to
the point that someone is contemplating catching ThreadDeath and doing
other equally-dubious things to work around issues created by the use of
Thread.stop().


No, I think RVic is just really, really new to Java. He's been posting
newbie type requests here for a couple of weeks or so. I think he's
just confused by "ThreadDeath" and wants to know what it means. That's all.
 
G

Gerald Murdock

markspace said:

Yes. In fact he got this specific advice elsewhere in this thread
regarding handling TD:

"By the way, if you catch ThreadDeath you must re-throw it when
you're through cleaning up. The obvious

try {
// thread stuff
} catch (ThreadDeath td) {
// clean up
throw td;
}

.... looks risky, because if the "clean up" throws something else the
ThreadDeath won't be re-thrown. On the assumption that it's more
important to "preserve" the ThreadDeath event than whatever else
happened, I'd suggest something like

try {
// thread stuff
} catch (ThreadDeath td) {
try {
// clean up
}
finally {
throw td;
}
}"
 
G

Gerald Murdock

Eric said:
My warning about the proper way to catch ThreadDeath is in no
way a proof that RVince planned to do so. His actual question was

"My question is how do I handle this? ... How do you handle
this "ThreadDeath" throwable in a try-catch block, and what do
you do with it afterwards?"

Thank you for making my point for me. :)
 
M

markspace

Eric said:
so the synchronization penalty is something
like 7.4 ns per operation.


This is a much smaller performance penalty that I was expecting. Given
that fact, I wouldn't hire the gang of interns either.

I guess the lesson here is that optimization really does require careful
measurement, not just guessing at the performance of a routine by
eyeball. ;)
 
L

Lew

markspace wrote: ...
Java pun] percolate gently through source tree.  And I'm not at all sure
I'd encourage wholesale changing of HashTable to HashMap

I presume you mean 'Hashtable' rather than 'HashTable'.
 
L

Lew

Eric said:
Lew said:
markspace wrote:
Eric said:
Neither HashTable nor StringBuffer is deprecated.
...
Java pun] percolate gently through source tree. And I'm not at all sure
I'd encourage wholesale changing of HashTable to HashMap

I presume you mean 'Hashtable' rather than 'HashTable'.

See what I said about non-zero risk? See? See?!!!

Well, if you did a wholesale search-and-replace of 'HashTable' to 'HashMap'
and the code hadn't used 'HashTable' but 'Hashtable' to begin with, you
wouldn't be introducing too much additional risk to your code.

Kidding aside, 'HashMap' is a close enough workalike to 'Hashtable' absent
multi-threaded concerns, as long as you take the extra step to convert any
associated 'Enumeration' into an 'Iterable' and replace any lost methods
('contains()', etc.). If the 'Map' is shared, you would want the
'Collections.synchronizedMap()' of it, or perhaps 'ConcurrentHashMap' (which
covers 'Hashtable' functionality, too, interestingly enough).

While Sun doesn't deprecate it, it does say about 'Hashtable's parent class,
'Dictionary', "This class is obsolete. New implementations should implement
the Map interface, rather than extending [sic] this class."

Personally I believe that we should all get rid of these obsolescent types -
HashMap, Vector, Enumeration, Dictionary - in favor of the replacement
Collection types. I'm smart enough to accept "where and when feasible".
 
L

Lew

Lew said:
[...]
Kidding aside, 'HashMap' is a close enough workalike to 'Hashtable'
absent multi-threaded concerns, as long as you take the extra step to
convert any associated 'Enumeration' into an 'Iterable' and replace
any lost methods ('contains()', etc.). If the 'Map' is shared, you
would want the 'Collections.synchronizedMap()' of it, or perhaps
'ConcurrentHashMap' (which covers 'Hashtable' functionality, too,
interestingly enough).

Eric said:
Another difference between Hashtable and HashMap is their behavior
with null keys and values: HashMap is happy with them, while Hashtable
throws NullPointerException. It'd be a pretty weird program that
relied on getting NPE from a Hashtable to find out about nulls, but
we know that the set of weird programs is non-empty ...

A more "practical" concern would likely be the different ways the
two implementations treat their chief tunables, load factor and initial
capacity. Somebody who's invested a lot of effort in choosing Just The
Right Size for his Hashtable, striking a delicate balance between lookup
time and iteration time, may be unhappy when HashMap inflates his
carefully-calculated size to the next power of two, potentially almost
doubling it.

You raise interesting points. My attitude was geared toward situations where
you could feasibly declare the variable as 'Map' and change implementation.
You describe situations where a very specific implementation is necessary, and
naturally my ideas wouldn't apply there. I've run into this sort of thing
recently where I needed to use 'ConcurrentHashMap' and the variable needed to
know that it was of that type.

Like so many other things in this business, the answer boils down to, "It
depends."
 
B

Bill McCleary

Eric said:
In code written before StringBuilder came along, I'd imagine. It
would (presumably) be possible to put a gang of interns on the task of
turning StringBuffers to StringBuilders throughout a large existing body
of code.

Nearly all StringBuffers are strictly local, so it would be possible to
put a gang of Python scripts on the task of turning StringBuffers to
StringBuilders throughout the entire source code of rt.jar, then test to
find the handful that need to be changed back, say by temporarily using
a StringBuilder class modified to throw a
ConcurrentModificationException upon concurrent use from multiple
threads, storing Thread.currentThread on construction and comparing
against same in every mutator, or perhaps just in every method and
running test coverage of every method that search tools found
StringBuffer in before the big replace, from two threads simultaneously,
to trigger the exceptions, logging which methods threw them.

Then it will take one guy a few minutes to change the StringBuilders in
the logged methods back, after it took him a few minutes to write the
above code and then leave it running overnight. :)
 
E

Eric Sosman

Eric said:
[...]

The cost of acquiring and releasing a StringBuffer's lock in the
absence of contention is pretty small. A quick measurement on my
desktop machine indicates 55.2 ns to append a three-character string to
a StringBuffer and then delete the three characters, 40.5 ns to do the
same to a StringBuilder, so the synchronization penalty is something
like 7.4 ns per operation. [...] (YMMV, obviously.)

At the risk of beating a dead horse, but I thought it
interesting: I ran the same test on a different machine and
got dramatically different results: 71 ns for StringBuilder
and *296* ns for StringBuffer, suggesting a synchronization
penalty of 112 ns per operation. "YMMV," indeed ...
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,262
Messages
2,571,056
Members
48,769
Latest member
Clifft

Latest Threads

Top