[snip some]
I'm not sure I care for your tone, mister. This feels like an attack
post, if not a particularly violent one, one meant to make me look
foolish in public perhaps. Watch it.
There's nothing special about thread-locals. Anything an object (say a
Thread) strongly references is reachable.
I just figured it wouldn't necessarily be obvious to someone fairly
new, if the fact the thread itself can't be collected isn't obvious to
the same person. Threadlocals aren't sitting in an obvious named place
as members of something after all. (Probably some Collection in the
Thread object, but who normally looks at the source code for Thread?
Especially newbies?)
Classes follow the same rules as other objects and can be collected.
If the local variable is dead (and remember actual execution is not
necessarily as it is written down in the source) is eligible.
Corner-cases. The local variable's referent can't be collected while
it's still in use by the running code, which is what's important.
Classes statically referenced all through the running code won't be
eligible either, and that's the vast majority of them. Dynamically
loaded classes you quit referencing might go, along with their
dependents not otherwise referenced, but that I expect is about it. To
top it off, the class is loaded again if there's an attempt to access
it again anyway, so the programmer shouldn't really "notice" its
absence, unless they keep WeakReferences to say a ResourceBundle
around to see if it ever turns null.
The really important thing is that it should simply not happen
(barring VM bugs, or reference objects) that something you're still
using disappears due to the garbage collector. This obviously includes
unnamed temporaries -- it's not just
new Thread(myRunnable).start();
it's even more common stuff like
myBigInteger.plus(anotherBigInteger).times(bigFactor);
the result of the "plus" is never held by any named variable, but it
won't be garbage-collected before the "times" is invoked on it. (This
happens most frequently with temporary Strings, although such code
should really be rewritten to use StringBuffer or StringBuilder if it
is responsible for a significant amount of CPU time or memory use on
profiling.)
One weird thing is the failure of the JVM to collect unreachable
Threads that have never run. It can't ever get run if no running code
can get ahold of a reference to it to call "start" on it, after all.
Just another reason to spawn threads lazily right when you run them, I
suppose (and this includes worker thread pools -- start them all right
away after constructing them, even if they immediately start waiting
on a BlockingQueue for work to do).