【问题标题】:How can I kill a thread? without using stop();我怎样才能杀死一个线程?不使用 stop();
【发布时间】:2011-08-20 09:15:03
【问题描述】:
Thread currentThread=Thread.currentThread();
        public void run()
        {               

             while(!shutdown)
            {                               
                try
                {
                    System.out.println(currentThread.isAlive());
                Thread.interrupted();

                System.out.println(currentThread.isAlive());
                if(currentThread.isAlive()==false)
                {
                    shutdown=true;
                }
                }
                catch(Exception e)
                {
                    currentThread.interrupt();
                }                   
            }
        }

    });
    thread.start();

【问题讨论】:

标签: java multithreading interrupted-exception interruption


【解决方案1】:

调用 stop 的替代方法是使用中断向线程发出信号,表明您希望它完成它正在做的事情。 (这假设您要停止的线程表现良好,如果它通过在抛出后立即吃掉它们来忽略 InterruptedExceptions 并且不检查中断状态,那么您将返回使用 stop()。)

这是我为回答线程问题here 而编写的一些代码,它是线程中断如何工作的示例:

public class HelloWorld {

    public static void main(String[] args) throws Exception {
        Thread thread = new Thread(new Runnable() {

            public void run() {
                try {
                    while (!Thread.currentThread().isInterrupted()) {
                        Thread.sleep(5000);
                        System.out.println("Hello World!");
                    }
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            }
        });
        thread.start();
        System.out.println("press enter to quit");
        System.in.read();
        thread.interrupt();
    }
}

需要注意的一些事项:

  • 中断会导致sleep() 和wait() 立即抛出,否则会卡住等待休眠时间过去。

  • 请注意,不需要单独的布尔标志。

  • 正在停止的线程通过检查中断状态并在 while 循环外捕获 InterruptedExceptions(使用它退出循环)进行协作。中断是一个可以使用异常进行流控制的地方,这就是它的全部意义所在。

  • 在 catch 块中的当前线程上设置中断在技术上是最佳实践,但对于本示例来说是多余的,因为没有其他需要设置中断标志的东西。

关于发布代码的一些观察:

  • 发布的示例不完整,但是将对当前线程的引用放在实例变量中似乎是个坏主意。它将被初始化为创建对象的任何线程,而不是执行 run 方法的线程。如果同一个 Runnable 实例在多个线程上执行,那么实例变量大部分时间都不会反映正确的线程。

  • 检查线程是否处于活动状态必然会导致结果为真(除非当前线程实例变量引用错误线程的错误),Thread#isAlive 只有在线程完成后才为假执行时,它不会因为被中断而返回 false。

  • 调用Thread#interrupted 将导致清除中断标志,在这里没有任何意义,特别是因为返回值被丢弃了。调用Thread#interrupted的目的是测试中断标志的状态,然后清除它,这是抛出InterruptedException的东西使用的方便方法。

【讨论】:

  • @Nathan:+1,如果我看到了这个答案,我什至不会费心自己写一个! gg
  • 首先,此代码假定将使用睡眠或其他可中断阻塞调用。不必如此。该代码可能会进行一些复杂的计算。使用线程中断需要更加小心。一些 IO 也可以被中断,如果有多个这样的 IO,我们可能需要仔细清理对象等。我建议一般使用标志变量作为更安全的选择。
  • @Raze:仅仅捕获阻塞 I/O 中断并中断当前线程就足够了吗?
  • 它肯定会停止线程,但是run()方法中的这个:{ try { while(...) {byte[] input = getChunkFromNetworkWhichHasCriticalData(); alertUser(input); } } catch(ClosedByInterruptException cbie) {...} }。两点:并非所有 IO 调用都被中断,因此它可能永远不会退出。如果调用将中断的 IO 调用,则处理部分获取的数据可能会很困难。在许多情况下,例如视频流,这不是问题。如果代码中有多个可中断点,它可能会变得更加复杂。
  • @Raze:绝对需要关心。这就是为什么我在示例中保留了 Thread.currentThread().interrupt() 以演示确保中断标志保持不变。无论如何,出于 OP 的目的,我认为该标志是不必要的,尽管它不会造成任何伤害,而且您的示例实施得很好。
【解决方案2】:

通常,线程在中断时终止。那么,为什么不使用 native boolean 呢?试试isInterrupted():

   Thread t = new Thread(new Runnable(){
        @Override
        public void run() {
            while(!Thread.currentThread().isInterrupted()){
                // do stuff         
            }   
        }});
    t.start();

    // Sleep a second, and then interrupt
    try {
        Thread.sleep(1000);
    } catch (InterruptedException e) {}
    t.interrupt();

【讨论】:

  • +1,人们喜欢自己滚动(布尔值),但你必须让它变得易变和 blar blar blar...使用像 isInterrupted 这样的标准中断策略感觉更优雅:D
  • 如果我调用threat.interrupt();不调用 Thread.sleep(1000) 会发生什么,这样安全吗?
【解决方案3】:

这样做的好方法是使用布尔标志来向线程发出信号。

class MyRunnable implements Runnable {

    public volatile boolean stopThread = false;

    public void run() {
            while(!stopThread) {
                    // Thread code here
            }
    }

}

创建一个名为 myrunnable 的 MyRunnable 实例,将其包装在一个新的 Thread 实例中并启动该实例。当你想标记线程停止时,设置 myrunnable.stopThread = true。这样,它就不会在某事的中间停止,只会在我们期望它停止的地方停止。

【讨论】:

  • 如果与阻塞队列结合使用取消标志可能会很危险。
  • @Luke,您是在谈论线程可能因为在队列中等待而无法退出的情况?
  • 是的,基本上,如果您在 while 循环中有一个像 queue.put 这样的阻塞操作,并且您的队列已满并且队列的所有消费者都已完成,那么即使您设置标志来停止您的任务也会获胜还没完。
  • @luke,对于任何使用 Object.wait 或许多 NIO 调用之一的操作都是如此,在这种情况下,可以根据情况使用 Nathan 的答案,也可以不添加标志。但是,这可能不适用于您的班级无权中断的系统(很少见,但我去过一次),更重要的是,在线程尚未启动的边缘情况下。
猜你喜欢
  • 2021-03-04
  • 2017-01-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多