4

A common question but I haven't found any acceptable answer.

I recently run in to the problem how to kill a thread in a nice way. I try to make a generic message handler that accepts runnables. The problem is that I can't exit the current runnable in a good way and fast enough.

The code in the runnables are unknown i.e. jni, pure java, 3:rd part lib etc. Below is a simple example with sleep that "steels" the interrupt so the thread never exits (fast enough): I wan't to be able to interrupt the thread at any time, only between each task are not acceptable. My first idea was to use thread.stop but that's deprecated.

Producer:

int i = 0;
MessageHandler handler = new MessageHandler();
handler.start();

handler.post(new Runnable() {
    @Override
    public void run() {
        System.out.println("task -" + i++ + " " + Thread.currentThread().getName());
        for (int r=0;r<1000000000;r++) {
            System.out.println("task -" + i++ + " " + Thread.currentThread().getName());
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
});

try {
    Thread.sleep(500);
} catch (InterruptedException q) {
    q.printStackTrace();
}
handler.interrupt();

Consumer (MessageHandler):

package test;

import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

public class MessageHandler extends Thread implements Runnable {

    private BlockingQueue<Runnable> msgQue = new LinkedBlockingQueue<Runnable>();
    private final static String TAG = "MessageHandler";

    public void run() {
        try {
            System.out.println(TAG + " Initialized "  + currentThread().getName());
            while(true) {
                Runnable task = msgQue.take();
                task.run();
                if (isInterrupted()) {
                    break;
                }
            }
        } catch (InterruptedException e) {
            System.out.println(TAG + " InterruptedException "  + currentThread().getName());
        } finally {
            System.out.println(TAG + " Exit "  + currentThread().getName());
            msgQue.clear();
            msgQue = null;
        }
    }

    public void post(Runnable task) {
        System.out.println(TAG + " post " + currentThread().getName());
        msgQue.add(task);
    }
}

I feel like a superman wihout any super power...

Hey, Oracle give my power back!

volt
  • 471
  • 1
  • 5
  • 12
  • "The code in the runnables are unknown i.e. jni, pure java, 3:rd part lib etc" - sounds to me like you want a process, not a thread. If it were a process, you could send it a signal to terminate. – Borealid Feb 05 '12 at 07:16
  • What's your outer problem? There's probably a good way to do whatever it is you want to do, but it probably has nothing to do with threads. (For example, what you probably want to do is stop some particular work from being done, which doesn't have anything to do with threads.) – David Schwartz Feb 05 '12 at 07:16

7 Answers7

3

Check out this faq on why they deprecated Thread.stop() and what to use instead. The gist of it is to use Thread.interrupt().

nfechner
  • 17,295
  • 7
  • 45
  • 64
  • My problem is that I might never receive the InterruptedException as it will be caught in the runner. As the runner might be a 3rd party lib I'm powerless! – volt Feb 05 '12 at 07:49
  • You are correct. The point the article is trying to make is, that you never had the power. `Thread.stop()` never worked reliable anyway. A malicious thread will always be able to prevent you from shutting it down. – nfechner Feb 06 '12 at 08:24
1

No, there is no safe way for a JVM to terminate an arbitrary thread. See the discussion on these questions:

Community
  • 1
  • 1
P.T.
  • 24,557
  • 7
  • 64
  • 95
0

I resolved this problem by using daemons ("a thread is daemon" means that it will be terminated once it's parent threat finnished): I created one more runnable class to control the desired runnable class.

class Interruptable implements Runnable {
    private Threat t;
    public Interruptable(Threat t) {
        this.t = t;
        this.t.setDeamon(true); //this is the important line
    }
    public void run() {
        this.t.start();
        while(true) {
            try {
                Thread.sleep(1);
            }
            catch(InterruptedException ex) {
                break;
            }
        }
    }
}

Now when the interruptable thread ends (by calling the interrupt method) the child threat if terminated as well because its a deamon.

PS: im not sure how to write Threat or Thread and im too lazy to google it :)

kajacx
  • 12,361
  • 5
  • 43
  • 70
0

You can either stop or interrupt the thread, and neither solution is perfect:

  1. Stopping simply kills it, but not only it can leave external resources in an inconsistent state (unclosed etc.), it can also leave the data structures of your program an inconsistent state. See Java Thread Primitive Deprecation. This can be quite serious, for example the inconsistency could be created in some core library and could cause problems throughout the whole application.
  2. Interrupting doesn't stop the thread until it checks for it (or some methods throw InterruptedException, which has to be explicitly caught). So if a thread doesn't check his interrupt state, it could remain running forever.

Generally, 1. is considered much worse, so it's why it's deprecated.

There is no ideal way how to solve the dilemma. Either you interrupt threads to make them exit gracefully, and then they can ignore the interrupt, or you kill them abruptly, and then no cleanup can be done.

One possibility how to somehow get the best of both is to interrupt a thread, wait for a few seconds, and then stop it abruptly. But I wouldn't recommend it, stopping simply isn't safe.

Another possibility would be to start your tasks in separate processes. This is complicated, you'll need to configure executable paths, different platforms might behave differently, etc. But the processes will be completely independent of your application, you can kill them safely and let the operating system do all the necessary cleanup.

Petr
  • 62,528
  • 13
  • 153
  • 317
0

With the cooperation of the code you are trying to stop, you can do it using any mechanism you want. Without the cooperation of that code, stopping a thread won't help. What if that thread was coordinating with some other thread? What if that thread caused the real work to be done in another process entirely?

David Schwartz
  • 179,497
  • 17
  • 214
  • 278
0

This is indeed a tedious problem. I might get downvoted for what I'm going to say, but I believe this fear of Thread.stop is sometimes not founded.

Since you mentioned that you know what the code that is going to be stopped is doing, then if you can ascertain that, if stopped abruptly, it would not leave any hanging resources (files, sockets, etc.), would not cause any kind of data corruption or would not cause any other thread to malfunction, then in my opinion it is perfectly safe to use Thread.stop.

Tudor
  • 61,523
  • 12
  • 102
  • 142
  • Actually he said that _The code in the runnables are unknown_. And, stopping threads can cause the application to get into unpredictable states, as explained in [Java Thread Primitive Deprecation](http://docs.oracle.com/javase/6/docs/technotes/guides/concurrency/threadPrimitiveDeprecation.html). – Petr Aug 29 '12 at 18:38
0

Instead of using queues and threads, you should just use an ExecutorService and submit tasks to it.

When you want it to stop, you can use the shutdown() method.

You can use stop() provided you understand why it is deprecated. It works just fine, but can have side effects. i.e. you have know what you are doing to use it.

BTW: This won't interrupt JNI calls. If you need that, you have to start a separate process which you kill -9 to be sure it will die.

Peter Lawrey
  • 525,659
  • 79
  • 751
  • 1,130