关于多线程:你如何杀死Java中的线程?

How do you kill a Thread in Java?

你如何杀死Java中的java.lang.Thread


请参阅Sun的这个主题,了解他们弃用的原因Thread.stop()。它详细说明了为什么这是一个糟糕的方法以及应该采取什么措施来安全地停止线程。

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


一般你不..

你要求它使用Thread.interrupt()(javadoc链接)中断它正在做的事情

这里有一个很好的解释为什么在javadoc(java技术说明链接)


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

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

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

Certain blocking library methods support interruption.

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

1
2
3
4
5
6
7
8
9
10
11
public void run() {
   try {
      while (!interrupted()) {
         // ...
      }
   } catch (InterruptedException consumed)
      /* Allow thread to exit */
   }
}

public void cancel() { interrupt(); }

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


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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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以"杀死"该线程。


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

1
2
3
4
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() );


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

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

  • 我投票给Thread.stop()

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

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

    所以无法强行停止一个奇怪的线程。


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

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


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

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


    没有办法优雅地杀死一个线程。

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

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    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");
                }

        }

    }

    1
    2
    3
    4
    5
    6
    7
    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/


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

    很简单。您可以在run()方法中使用任何循环和(volatile)布尔变量来控制线程的活动。您也可以从活动线程返回到主线程以停止它。

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


    "杀死一个帖子"不是一个合适的短语。这是我们可以在will上实现线程的优雅完成/退出的一种方式:

    我使用的Runnable:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    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;
        }

    }

    触发类:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    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");

        }

    }

    这里有几个关于这个主题的好读物:

    你怎么处理InterruptedException?

    干净地关闭线程


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

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

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

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

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


    我没有让中断在Android中工作,所以我使用这个方法,完美地工作:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    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;
     }