Are Thread.stop and friends ever safe in Java?

Here's my attempt at answering my own question.

I think that the following conditions should be sufficient for a single thread to be safely stopped using Thread.stop():

  1. The thread execution must not create or mutate any state (i.e. Java objects, class variables, external resources) that might be visible to other threads in the event that the thread is stopped.
  2. The thread execution must not use notify to any other thread during its normal execution.
  3. The thread must not start or join other threads, or interact with then using stop, suspend or resume.

(The term thread execution above covers all application-level code and all library code that is executed by the thread.)

The first condition means that a stopped thread will not leave any external data structures or resources in an inconsistent state. This includes data structures that it might be accessing (reading) within a mutex. The second condition means that a stoppable thread cannot leave some other thread waiting. But it also forbids use of any synchronization mechanism other that simple object mutexes.

A stoppable thread must have a way to deliver the results of each computation to the controlling thread. These results are created / mutated by the stoppable thread, so we simply need to ensure that they are not visible following a thread stop. For example, the results could be assigned to private members of the Thread object and "guarded" with a flag that is atomically by the thread to say it is "done".

EDIT: These conditions are pretty restrictive. For example, for a "regex evaluator" thread to be safely stopped, if we must guarantee that the regex engine does not mutate any externally visible state. The problem is that it might do, depending on how you implement the thread!

  1. The Pattern.compile(...) methods might update a static cache of compiled patterns, and if they did they would (should) use a mutex to do it. (Actually, the OpenJDK 6.0 version doesn't cache Patterns, but Sun might conceivably change this.)
  2. If you try to avoid 1) by compiling the regex in the control thread and supplying a pre-instantiated Matcher, then the regex thread does mutate externally visible state.

In the first case, we would probably be in trouble. For example, suppose that a HashMap was used to implement the cache and that the thread was interrupted while the HashMap was being reorganized.

In the second case, we would be OK provided that the Matcher had not been passed to some other thread, and provided that the controller thread didn't try to use the Matcher after stopping the regex matcher thread.

So where does this leave us?

Well, I think I have identified conditions under which threads are theoretically safe to stop. I also think that it is theoretically possible to statically analyse the code of a thread (and the methods it calls) to see if these conditions will always hold. But, I'm not sure if this is really practical.

Does this make sense? Have I missed something?

EDIT 2

Things get a bit more hairy when you consider that the code that we might be trying to kill could be untrusted:

  1. We can't rely on "promises"; e.g. annotations on the untrusted code that it is either killable, or not killable.

  2. We actually need to be able to stop the untrusted code from doing things that would make it unkillable ... according to the identified criteria.

I suspect that this would entail modifying JVM behaviour (e.g. implementing runtime restrictions what threads are allowed to lock or modify), or a full implementation of the Isolates JSR. That's beyond the scope of what I was considering as "fair game".

So lets rule the untrusted code case out for now. Or at least, acknowledge that malicious code can do things to render itself not safely killable, and put that problem to one side.


The lack of safety comes from the idea idea of critical sections

Take mutex

do some work, temporarily while we work our state is inconsistent

// all consistent now

Release mutex

If you blow away the thread and it happend to be in a critical section then the object is left in an inconsistent state, that means not safely usable from that point.

For it to be safe to kill the thread you need to understand the entire processing of whatever is being done in that thread, to know that there are no such critical sections in the code. If you are using library code, then you may not be able to see the source and know that it's safe. Even if it's safe today it may not be tomorrow.

(Very contrived) Example of possible unsafety. We have a linked list, it's not cyclic. All the algorithms are really zippy because we know it's not cyclic. During our critical section we temporarily introduce a cycle. We then get blown away before we emerge from the critical section. Now all the algorithms using the list loop forever. No library author would do that surely! How do you know? You cannot assume that code you use is well written.

In the example you point to, it's surely possible to write the requreid functionality in an interruptable way. More work, but possible to be safe.

I'll take a flyer: there is no documented subset of Objects and methods that can be used in cancellable threads, because no library author wants to make the guarantees.