Re: What is so bad aboud Thread.stop() ?
On Tuesday, August 13, 2013 6:22:33 PM UTC-4, Lew wrote:
taq...@gmail.com wrote:
I am trying to see what is new that Thread.stop brings to that consider=
ation
versus other mundane and accepted Thread interactions.
Seems to me that
http://docs.oracle.com/javase/6/docs/technotes/guides/concurrency/threadP=
rimitiveDeprecation.html
explains it rather well.
I found it fast via
http://lmgtfy.com/?q=Java+dangers+of+Thread.stop
You've cited part of this, presumably from the Javadocs:
"This method is inherently unsafe. Stopping a thread with Thread.stop cau=
ses it to unlock all of the
monitors that it has locked (as a natural consequence of the unchecked Th=
readDeath exception
propagating up the stack). If any of the objects previously protected by =
these monitors were in an
inconsistent state, the damaged objects become visible to other threads, =
potentially resulting in
arbitrary behavior."
I'm not sure what else you need to know here. This is both normative and =
complete.
--
Lew
As discussed above in the thread my interest was that -- as this excerpt it=
self implies -- using Thread.stop merely initiates an exception which is th=
en handled just as any other exception is. So what's special about it? In =
all of our discussion we seem to have only two characteristics that are spe=
cial. The first is that ThreadDeath will not normally cause an error messa=
ge. That seems pretty trivial. The second is that the exception can in pr=
inciple happen anywhere in the stopped thread. However if it were easy to =
stop threads only in some TBD safe zone then it seems that using Thread.sto=
p could be done robustly.
Since it seems that most commenters have limited experience with Thread.sto=
p I've played a little with it myself. E.g., a test monitor class creates a=
set of worker threads. Each worker thread requests a task from the monito=
r, executes the task, reports the result back to the monitor, then asks for=
the next task. The monitor periodically kills all threads older than some=
arbitrary value and creates a new replacement, caching the task that got c=
ancelled to be rerun. The worker threads are only stoppable during the ex=
ecution phase. Here's one of the classes:
package threadstoptester;
public class StoppableThread extends Thread {
private volatile boolean isStoppable = false;
private volatile boolean running = true;
synchronized protected void stoppable(boolean flag) {
if (!flag && !running) {
// Don't proceed to nonstoppable state if
// someone has already stopped the thread.
throw new ThreadDeath();
}
isStoppable = flag;
}
synchronized protected boolean running() {
return running;
}
synchronized public boolean doStop() {
if (isStoppable) {
isStoppable = false;
running = false;
this.stop();
return true;
} else {
return false;
}
}
}
The worker threads inherit this class, and the monitor thread calls the doS=
top method on the appropriate worker thread object which in turn calls Thre=
ad.stop
on the appropriate thread if the thread is currently stoppable.
My fairly simple implementation seems to run fine. Note that although it's=
not especially complex, in terms of thread interactions this is much more =
involved than what I would normally do. Generally I just start one thread =
to do one task and throw it away when it's done. So this seems like a fair=
test of whether there are some circumstances we can use Thread.stop robust=
ly.
Of course I haven't proved anything... There could be subtle (or given my =
multithreading experience, obvious) bugs that just haven't surfaced in my l=
imited testing. I've killed as many as ~40K threads so one might hope prob=
lems might emerge. Still so far this is play. But it doesn't suggest that=
programs are necessarily unstable when using Thread.stop, even promiscuous=
ly.
So where might this approach be useful:
1. Testing/running code that might include infinite loops due to bugs or =
user inputs.
- Better if single threaded
- Limited access to code
- Don't want overhead of starting new VM for each test
(or need some level of communication that makes separate VM inconve=
nient)
2. Stopping out of control tasks in some existing executor framework (e.g=
.., web server) where we need to clean up wayward threads.
- need to be able to identify 'stoppable' regions which may be hard.
3. As a potentially attractive alternative to the cooperative stopping me=
chanism in certain cases.
- When substantial code base might be implicated in cooperative appro=
ach.
- May require sandbox like approach.
The third alternative (and indeed all three) will be controversial, so I'll=
close with an amplification of what I'm thinking there.
The cooperative Thread.interrupt() approach implies that the code that migh=
t be interrupted knows about this, i.e., the worker code is aware that ther=
e is some monitor. It needs to periodically check the interrupt flag and =
do something. This couples the invoker to the invoked in a way that's a bi=
t unattractive. It's no big deal if it's just a simple loop to check but i=
f there are lots of classes and methods that need to be instrumented it's n=
ot elegant.
If one has a set of code that is running where it's known that the invoking=
threads are not affected except in some clearly defined way by the worker =
threads (e.g. a kind of sandbox), then using Thread.stop potentially decoup=
les the monitor/invoker process from the worker code. In the right circums=
tances, I can imagine this being more attractive. My limited testing sugge=
sts that those circumstances need not be the null set.
That's not to say that others will or should agree with any of this, but th=
anks to both the user comments and my own explorations, I think I understan=
d the issues much better. I'm intrigued by the responses discussing ways t=
o do this that all the creation of dynamic objects that would be safe even =
in the presence of Thread.stop -- but that's probably more than I need to w=
orry about now.
Thanks to all.
Regards,
Tom McGlynn