你如何杀死Java中的线程?

时间:2009-03-22 14:04:35

标签: java multithreading join interrupt

如何在Java中杀死java.lang.Thread

16 个答案:

答案 0 :(得分:178)

thread by Sun on why they deprecated Thread.stop()。它详细说明了为什么这是一个糟糕的方法以及应该采取什么措施来安全地停止线程。

他们推荐的方法是使用共享变量作为标志,要求后台线程停止。然后,该变量可以由请求线程终止的不同对象设置。

答案 1 :(得分:126)

一般情况下你不.. ..

你要求它使用Thread.interrupt() (javadoc link)

打断它正在做的事情

为什么在javadoc here (java technote link)

中有一个很好的解释

答案 2 :(得分:63)

在Java线程中没有被杀死,但是线程的停止是以合作方式完成的。要求线程终止,然后线程可以正常关闭。

通常使用volatile boolean字段,当线程设置为相应的值时,线程会定期检查并终止。

不会使用boolean检查线程是否应终止。如果你使用volatile作为字段修饰符,这将是可靠的,但如果你的代码变得更复杂,而是使用while循环内的其他阻塞方法,可能会发生,你的代码会<强烈>不终止或者至少需要更长时间

  

某些阻止库方法支持中断。

每个线程都有一个布尔标志中断状态,你应该使用它。它可以像这样实现:

public void run() {
   try {
      while (!interrupted()) {
         // ...
      }
   } catch (InterruptedException consumed)
      /* Allow thread to exit */
   }
}

public void cancel() { interrupt(); }

源代码改编自Java Concurrency in Practice。由于cancel()方法是公共的,您可以让另一个线程根据需要调用此方法。

答案 3 :(得分:18)

一种方法是设置一个类变量并将其用作哨兵。

Class Outer {
    public static volatile flag = true;

    Outer() {
        new Test().start();
    }
    class Test extends Thread {

        public void run() {
            while (Outer.flag) {
                //do stuff here
            }
        }
    }

}

在上面的例子中设置一个外部类变量,即flag = true。将其设置为false以“杀死”该线程。

答案 4 :(得分:11)

有一种方法可以做到这一点。但是如果你不得不使用它,要么你是一个糟糕的程序员,要么你正在使用由坏程序员编写的代码。所以,你应该考虑停止成为一个糟糕的程序员或停止使用这个糟糕的代码。 此解决方案仅适用于没有其他方式的情况。

Thread f = <A thread to be stopped>
Method m = Thread.class.getDeclaredMethod( "stop0" , new Class[]{Object.class} );
m.setAccessible( true );
m.invoke( f , new ThreadDeath() );

答案 5 :(得分:8)

我想基于已经积累的评论添加几个观察结果。

  1. 如果安全管理器允许,则Thread.stop()将停止一个线程。
  2. Thread.stop()很危险。话虽如此,如果您在JEE环境中工作并且无法控制所调用的代码,则可能是必要的。
  3. 您永远不应该停止停止容器工作线程。如果你想运行倾向于挂起的代码,(小心)启动一个新的守护程序线程并对其进行监视,必要时进行查杀。
  4. stop()在调用线程上创建一个新的ThreadDeath错误,然后将该错误应用于目标线程。因此,堆栈跟踪通常毫无价值。
  5. 在JRE 6中,stop()检查安全管理器,然后调用调用stop0()的stop1()。 stop0()是本机代码。

答案 6 :(得分:7)

我投票给Thread.stop()

例如,您有一个持久的操作(如网络请求)。 据说您正在等待响应,但可能需要一些时间并且用户导航到其他UI。 这个等待的线程现在是a)无用的b)潜在的问题,因为当他得到结果时,它完全没用,并且他将触发可能导致错误数量的回调。

所有这一切,他可以进行可能CPU密集的响应处理。而且,作为开发人员,您甚至无法阻止它,因为您无法在所有代码中抛出if (Thread.currentThread().isInterrupted())行。

所以无法强行停止线程这很奇怪。

答案 7 :(得分:5)

这个问题很模糊。如果你的意思是“如何编写一个程序,以便在我想要的时候线程停止运行”,那么其他各种响应应该会有所帮助。但是,如果你的意思是“我有一个服务器的紧急情况我现在无法重启,我只需要一个特定的线程就可以死”,那么你需要一个干预工具来匹配jstack等监控工具。 / p>

为此,我创建了jkillthread。请参阅其使用说明。

答案 8 :(得分:4)

当然,您正在运行某种不完全信任的代码。 (我个人有这个允许上传的脚本在我的Java环境中执行。是的,到处都有安全警报响铃,但它是应用程序的一部分。)在这个不幸的例子中,你首先要求脚本编写者充满希望尊重某种布尔运行/不运行信号。你唯一合适的失败保险是在线程上调用stop方法,比如说,它运行时间超过一些超时。

但是,这只是“体面”,而不是绝对的,因为代码可以捕获ThreadDeath错误(或者你明确抛出的任何异常),而不是像绅士线程那样重新抛出它。所以,底线是AFAIA,没有绝对的失败安全。

答案 9 :(得分:3)

没有办法优雅地杀死一个帖子。

你可以尝试中断线程,一个公共策略是使用毒丸来消息线程自行停止

public class CancelSupport {
    public static class CommandExecutor implements Runnable {
            private BlockingQueue<String> queue;
            public static final String POISON_PILL  = “stopnow”;
            public CommandExecutor(BlockingQueue<String> queue) {
                    this.queue=queue;
            }
            @Override
            public void run() {
                    boolean stop=false;
                    while(!stop) {
                            try {
                                    String command=queue.take();
                                    if(POISON_PILL.equals(command)) {
                                            stop=true;
                                    } else {
                                            // do command
                                            System.out.println(command);
                                    }
                            } catch (InterruptedException e) {
                                    stop=true;
                            }
                    }
                    System.out.println(“Stopping execution”);
            }

    }

}

BlockingQueue<String> queue=new LinkedBlockingQueue<String>();
Thread t=new Thread(new CommandExecutor(queue));
queue.put(“hello”);
queue.put(“world”);
t.start();
Thread.sleep(1000);
queue.put(“stopnow”);

http://anandsekar.github.io/cancel-support-for-threads/

答案 10 :(得分:2)

通常,您不会杀死,停止或中断线程(或检查线程是否被中断()),而应让其自然终止。

很简单。您可以在run()方法中将任何循环与(易失性)布尔变量一起使用,以控制线程的活动。您也可以从活动线程返回主线程以停止它。

这样,您可以优雅地杀死一个线程:)。

答案 11 :(得分:1)

突然线程终止的尝试是众所周知的错误的编程实践和应用程序设计不佳的证据。多线程应用程序中的所有线程显式和隐式地共享相同的进程状态,并被迫相互合作以保持一致,否则您的应用程序将容易出现很难诊断的错误。因此,开发人员有责任通过仔细而清晰的应用程序设计来保证这种一致性。

受控线程终端有两种主要的正确解决方案:

  • 使用共享易失性标志
  • 使用一对Thread.interrupt()和Thread.interrupted()方法。

有关突发线程终止的问题的详细解释以及受控线程终止的错误和正确解决方案示例可在此处找到:

https://www.securecoding.cert.org/confluence/display/java/THI05-J.+Do+not+use+Thread.stop%28%29+to+terminate+threads

答案 12 :(得分:1)

以下是关于这个主题的几个好读物:

What Do You Do With InterruptedException?

Shutting down threads cleanly

答案 13 :(得分:1)

“杀死线程”不是正确的用法。这是我们可以按意愿实现线程的正常完成/退出的一种方法:

我使用过的Runnable:

class TaskThread implements Runnable {

    boolean shouldStop;

    public TaskThread(boolean shouldStop) {
        this.shouldStop = shouldStop;
    }

    @Override
    public void run() {

        System.out.println("Thread has started");

        while (!shouldStop) {
            // do something
        }

        System.out.println("Thread has ended");

    }

    public void stop() {
        shouldStop = true;
    }

}

触发类:

public class ThreadStop {

    public static void main(String[] args) {

        System.out.println("Start");

        // Start the thread
        TaskThread task = new TaskThread(false);
        Thread t = new Thread(task);
        t.start();

        // Stop the thread
        task.stop();

        System.out.println("End");

    }

}

答案 14 :(得分:0)

我没有在Android中使用中断,所以我使用了这种方法,效果很好:

boolean shouldCheckUpdates = true;

private void startupCheckForUpdatesEveryFewSeconds() {
    Thread t = new Thread(new CheckUpdates());
    t.start();
}

private class CheckUpdates implements Runnable{
    public void run() {
        while (shouldCheckUpdates){
            //Thread sleep 3 seconds
            System.out.println("Do your thing here");
        }
    }
}

 public void stop(){
        shouldCheckUpdates = false;
 }

答案 15 :(得分:0)

不建议使用Thread.stop,那么如何在Java中停止线程?

始终使用中断方法和将来请求取消

  1. 当任务响应中断信号时,例如,阻塞队列获取方法。
Callable < String > callable = new Callable < String > () {
    @Override
    public String call() throws Exception {
        String result = "";
        try {
            //assume below take method is blocked as no work is produced.
            result = queue.take();
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
        return result;
    }
};
Future future = executor.submit(callable);
try {
    String result = future.get(5, TimeUnit.SECONDS);
} catch (TimeoutException e) {
    logger.error("Thread timedout!");
    return "";
} finally {
    //this will call interrupt on queue which will abort the operation.
    //if it completes before time out, it has no side effects
    future.cancel(true);
}

  1. 当任务不响应中断信号时,假设任务执行了不响应中断信号的套接字I / O,因此使用上述方法不会中止任务,将来会超时,但是在finally块中取消没有效果,线程将继续监听套接字。如果由pool实现,我们可以关闭套接字或在连接上调用close方法。
public interface CustomCallable < T > extends Callable < T > {
    void cancel();
    RunnableFuture < T > newTask();
}

public class CustomExecutorPool extends ThreadPoolExecutor {
    protected < T > RunnableFuture < T > newTaskFor(Callable < T > callable) {
        if (callable instanceof CancellableTask)
            return ((CancellableTask < T > ) callable).newTask();
        else
            return super.newTaskFor(callable);
    }
}

public abstract class UnblockingIOTask < T > implements CustomCallable < T > {
    public synchronized void cancel() {
        try {
            obj.close();
        } catch (IOException e) {
            logger.error("io exception", e);
        }
    }

    public RunnableFuture < T > newTask() {
        return new FutureTask < T > (this) {
            public boolean cancel(boolean mayInterruptIfRunning) {
                try {
                    this.cancel();
                } finally {
                    return super.cancel(mayInterruptIfRunning);
                }
            }

        };
    }
}