2

The prevailing religion of Java today heavily forbids the use of the stop() instance method on a Thread[1] [2] [3]. It's marked as Deprecated in the official documentation, with a message that begins with:

This method is inherently unsafe. Stopping a thread with Thread.stop causes it to unlock all of the monitors that it has locked (as a natural consequence of the unchecked ThreadDeath 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. [...]

There is even a whole article supplied that goes into further detail. (Especially that ThreadDeath is silent when it gets to the top, and even if you guard against it, you can't guard against Thread.stop(Throwable t) anyway.)

In general, I agree with what that article is worried about, and with the answers to the related question on StackOverflow — in almost all the use cases in the world there is a much better way than stop(). But not all.

Here is a use case that I'm struggling to think of a better way for. I invite your suggestions.

Use case

I'm working with an interactive console running on top of Java, that allows the user run arbitrary Java statements and Python functions that call Java, in an interactive interpreted way. (See Jython console for screenshots.)

Now, the user can write arbitrary functions. Some of them might call Java methods that result in infinite loops that print a lot of output, almost saturating the system, so that it becomes painfully slow to respond.

When the user messes up like this, I need to give them a chance to kill the thread (using a button), and salvage the remainder of the work that they have produced in their session and stored in local variables.

If calling interrupt() on the thread fails, (e.g. if it never goes into waiting state while stuck in its infinite loop), then we are faced with two options that I can see: (1) kill the application outright or (2) use stop() on the bad thread, and let the user salvage whatever is left that hadn't been corrupted.

Yes I know that some objects may have been damaged and won't work properly. But we're talking about salvaging anything that may have been left in a valid state (which is probably pretty much everything, except one or two things).

Can anybody see any problems with this reasoning? And if this turns out to be a valid use-case, then does it mean the method shouldn't be deprecated :) ?

Community
  • 1
  • 1
Evgeni Sergeev
  • 22,495
  • 17
  • 107
  • 124
  • 2
    We cannot really speculate as to what might happen. All you can do is try it and see if the consequences are acceptable in your use case, which is really what you should have tried before posting. – Jim Garrison Feb 27 '16 at 08:06
  • 1
    @JimGarrison Thanks Jim, have you read the question properly? – Evgeni Sergeev Feb 27 '16 at 08:26
  • 2
    It is deprecated for all the reasons given. You can choose to use it but are responsible for the consequences. Maybe the consequences are acceptable to you, but we can't predict what those consequences will be, since they'll depend on the code written by your users. Are you asking someone here to bless your approach? In that case the question is probably off-topic as "opinion-based" since there's nothing on which to base an answer except for all that's been written about it being deprecated. – Jim Garrison Feb 27 '16 at 08:32
  • 1
    @JimGarrison I guess the point of asking is something like this: I'm about to implement this, and everything I read says "NEVER DO THIS!!!", like [the answer I linked](http://stackoverflow.com/a/25984377/1143274). I don't have 10+ years of experience as a full-time Java developer, but there are thousands of S.O. users who do. And a response such as "Yes, there is no better way that I know of" from somebody with a deep understanding of Java multithreading, is valuable. So if I haven't missed anything, the question will rewrite the rule book to say "NEVER *except in the scenario of salvaging". – Evgeni Sergeev Feb 27 '16 at 09:11
  • And the scenario of salvaging isn't all that uncommon. So the question seems significant enough to post. – Evgeni Sergeev Feb 27 '16 at 09:11
  • 2
    The safest option is to start a JVM to run your program each time, which will allow you to kill the process and a full cleanup. e.g. I could write `for(int i=0;;i++) System.setProperty(""+i, ""+i);` and you can clean up my thread but not the damage done. – Peter Lawrey Feb 27 '16 at 10:52
  • @PeterLawrey That would work if I could pass anything into the new JVM, such as an open file handle pointing somewhere in the middle of a file. The user can do anything and from their point of view, the state persists between commands. Issues like that prevent running each command in a different process. I wonder what would be a long-term solution — because with today's architectures a little bad code can bring down a program, or even crash the operating system. Clearly, it would have to be something very different from what we have today. It would have to detect problems, and contain damage. – Evgeni Sergeev Feb 28 '16 at 07:41
  • @EvgeniSergeev you should be passing a partially read file from one method to another, so the fact it does work between processes in Java (note it does work in C) shouldn't be an impediment. Run in a separate process at least allows you to kill and clean it up in a self contained way, esp if you limit its access to IO which Java's Security manager can do. – Peter Lawrey Feb 28 '16 at 09:45

1 Answers1

0

Calling Thread.stop() is a bad idea. End of story.

It may work in practice but you sacrifice most of the JVM's concurrency guarantees in the process. Your whole program is essentially running undefined behavior. It isn't simply the thread or the data in the thread that may become corrupted, but any part of the JVM that happens to be in a vulnerable state when the thread is killed.

It sounds like you're looking for someone to confirm that your use case somehow avoids the risks to the JVM. It doesn't, so you're not likely to get such a confirmation. If you don't see issues more power to you, but don't be surprised when it fails in inexplicable or dangerous ways.

As Peter Lawrey suggests you should be running this untrusted code in an isolated JVM, where the OS's process management can support killing resource-hogging processes. If you can't do that because you're passing around strange resources like open file descriptors that is your problem.

dimo414
  • 47,227
  • 18
  • 148
  • 244