Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Are Thread.stop and friends ever safe in Java?

The stop(), suspend(), and resume() in java.lang.Thread are deprecated because they are unsafe. The Oracle recommended work around is to use Thread.interrupt(), but that approach doesn't work in all cases. For example, if you are call a library method that doesn't explicitly or implicitly check the interrupted flag, you have no choice but to wait for the call to finish.

So, I'm wondering if it is possible to characterize situations where it is (provably) safe to call stop() on a Thread. For example, would it be safe to stop() a thread that did nothing but call find(...) or match(...) on a java.util.regex.Matcher?

(If there are any Oracle engineers reading this ... a definitive answer would be really appreciated.)

EDIT: Answers that simply restate the mantra that you should not call stop() because it is deprecated, unsafe, whatever are missing the point of this question. I know that that it is genuinely unsafe in the majority of cases, and that if there is a viable alternative you should always use that instead.

This question is about the subset cases where it is safe. Specifically, what is that subset?

like image 761
Stephen C Avatar asked Aug 16 '09 02:08

Stephen C


People also ask

Why was stop method in thread deprecated?

Certain thread APIs were introduced to facilitate thread suspension, resumption, and termination but were later deprecated because of inherent design weaknesses. For example, the Thread. stop() method causes the thread to immediately throw a ThreadDeath exception, which usually stops the thread.

Does a thread automatically be killed?

A thread is automatically destroyed when the run() method has completed. But it might be required to kill/stop a thread before it has completed its life cycle.

What will be the best way to stop a Java thread?

Whenever we want to stop a thread from running state by calling stop() method of Thread class in Java. This method stops the execution of a running thread and removes it from the waiting threads pool and garbage collected.

How do you know if thread safe?

A method will be thread safe if it uses the synchronized keyword in its declaration.


1 Answers

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.

like image 191
Stephen C Avatar answered Oct 10 '22 18:10

Stephen C