一个常见问题,但我没有找到任何可接受的答案。
我最近遇到了如何以一种很好的方式杀死一个线程的问题。 我尝试创建一个接受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);
}
}
我觉得自己像超人一样没有任何超能力......
嘿,甲骨文给了我力量!答案 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)
您可以停止或中断线程,这两种解决方案都不是完美的:
InterruptedException
,必须明确捕获它。因此,如果一个线程没有检查他的中断状态,它可能会一直运行。通常情况下,1被认为更糟糕,因此它被弃用了。
如何解决困境没有理想的方法。要么中断线程以使它们正常退出,然后它们可以忽略中断,或者你突然终止它们,然后就不能进行清理。
如何以某种方式获得最佳效果的一种可能性是中断线程,等待几秒钟,然后突然停止它。但我不推荐它,停止只是不安全。
另一种可能性是在不同的流程中启动您的任务。这很复杂,您需要配置可执行路径,不同平台可能会有不同的行为等。但是这些进程将完全独立于您的应用程序,您可以安全地终止它们并让操作系统进行所有必要的清理。