如何在java中杀死一个好的线程?

时间:2012-02-05 07:08:36

标签: java multithreading

一个常见问题,但我没有找到任何可接受的答案。

我最近遇到了如何以一种很好的方式杀死一个线程的问题。 我尝试创建一个接受runnables的通用消息处理程序。 问题是我无法以足够快的速度退出当前的runnable。

runnables中的代码是未知的,即jni,纯java,3:rd part lib等。 下面是一个简单的示例,其中睡眠会“中断”中断,因此线程永远不会退出(足够快): 我不能随时打断线程,只能在每个任务之间接受。 我的第一个想法是使用thread.stop但不推荐使用。

制片:

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();
消费者(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);
    }
}

我觉得自己像超人一样没有任何超能力......

嘿,甲骨文给了我力量!

7 个答案:

答案 0 :(得分:3)

查看why they deprecated Thread.stop()上的常见问题解答以及使用的内容。它的要点是使用Thread.interrupt()

答案 1 :(得分:1)

不,JVM没有安全的方法来终止任意线程。请参阅有关这些问题的讨论:

答案 2 :(得分:0)

通过您尝试停止的代码的合作,您可以使用您想要的任何机制来完成。没有该代码的合作,停止一个线程将无济于事。如果该线程与其他线程协调怎么办?如果那个线程完全在另一个进程中完成了真正的工作会怎么样?

答案 3 :(得分:0)

这确实是一个乏味的问题。我可能会因为我要说的话而被投票,但我相信这种对Thread.stop的恐惧有时没有成立。

既然你提到你知道要停止的代码是做什么的,那么如果你能确定,如果突然停止,它就不会留下任何挂起的资源(文件,套接字等),不会导致任何类型的数据损坏或不会导致任何其他线程出现故障,那么在我看来使用Thread.stop是完全安全的。

答案 4 :(得分:0)

您应该只使用ExecutorService并向其提交任务,而不是使用队列和线程。

如果要停止,可以使用shutdown()方法。

如果您了解不推荐使用的原因,可以使用stop()。它工作得很好,但可能有副作用。即你已经知道你在做什么来使用它。

BTW:这不会中断JNI呼叫。如果您需要,您必须开始一个单独的过程,kill -9确保它会死亡。

答案 5 :(得分:0)

我通过使用守护进程解决了这个问题(“一个线程是守护进程”意味着一旦它的父威胁完成它就会被终止):我创建了一个可运行的类来控制所需的runnable类。

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;
            }
        }
    }
}

现在,当可中断线程结束时(通过调用中断方法)子威胁如果被终止也是因为它是一个守护进程。

PS:我不知道如何编写威胁或线程,我也懒得谷歌吧:)

答案 6 :(得分:0)

您可以停止中断线程,这两种解决方案都不是完美的:

  1. 停止只是杀死它,但不仅它可以使外部资源处于不一致状态(未封闭等),它还可能使程序的数据结构处于不一致状态。见Java Thread Primitive Deprecation。这可能非常严重,例如,可能会在某个核心库中创建不一致,并可能在整个应用程序中引起问题。
  2. 中断不会停止线程,直到它检查它(或某些方法抛出InterruptedException,必须明确捕获它。因此,如果一个线程没有检查他的中断状态,它可能会一直运行。
  3. 通常情况下,1被认为更糟糕,因此它被弃用了。

    如何解决困境没有理想的方法。要么中断线程以使它们正常退出,然后它们可以忽略中断,或者你突然终止它们,然后就不能进行清理。

    如何以某种方式获得最佳效果的一种可能性是中断线程,等待几秒钟,然后突然停止它。但我不推荐它,停止只是不安全。

    另一种可能性是在不同的流程中启动您的任务。这很复杂,您需要配置可执行路径,不同平台可能会有不同的行为等。但是这些进程将完全独立于您的应用程序,您可以安全地终止它们并让操作系统进行所有必要的清理。