如何在Java中停止正在运行的线程

6
我正在使用一款基于Java的文件转换工具,它可以将PDF转换为DOCX,但有时会出现卡顿的情况,如果输入文件大小超过1 MB,则开始占用100%的CPU和更多内存,并继续运行。我想要停止这个持续的线程。
  1. 我知道 stop() 函数已弃用。
  2. 调用 thread.interrupt(); 没有帮助,因为线程仍然在运行。
  3. 代码中没有循环...所以无法在循环中检查是否被中断。

如何停止正在运行的线程 t。

public class ThreadDemo implements Runnable {

    Thread t;

    PdfToDocConversion objPdfToDocConversion;

    ThreadDemo() throws InterruptedException {

        t = new Thread(this);
        System.out.println("Executing " + t.getName());
        // this will call run() fucntion
        t.start();

        Thread.sleep(2000);

        // interrupt the threads
        if (!t.interrupted()) {
            System.out.println("Interrupted");

            t.interrupt();

        }

        System.out.println(t.isInterrupted()); // true 

        System.out.println(t.getName());

        System.out.println(t.isAlive());   /// still true 

        // block until other threads finish
        try {
            t.join();
        } catch (InterruptedException e) {
        }
    }

    public void run() {

        objPdfToDocConversion = new PdfToDocConversion();
        try {


    objPdfToDocConversion.convertDocToPdf();//inside this function thread got stuck

        } catch (InterruptedException e) {

            Thread.currentThread().interrupt(); 
            System.out.print(t.getName() + " interrupted:");
            e.printStackTrace();
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    public static void main(String args[]) {
        try {
            new ThreadDemo();
        } catch (InterruptedException e) {
                e.printStackTrace();
        }
    }
}

我不是专家,但我认为你永远不应该尝试停止线程。相反,让它自己完成。 - Nabin
可能是如何在Java中终止线程?的重复问题。 - Aleksandr Erokhin
3个回答

4

通过使用 boolean 标志,您可以构建自己的逻辑来结束线程。

public class RunningThread implements Thread {

   private volatile boolean running = true;

   public void run() {

     while (running) {
        try {
            // Add your code here
        } catch (InterruptedException e) {
             if(!running){
                break;
             }
        }
     }
   }

   public void stopThread() {
       running = false;
       interrupt();
   }

}

以下是使用案例:

RunningThread thread = new RunningThread();
thread.start(); // start the thread
thread.stopThread(); // stops the thread

上述方法最初由谷歌开发人员在其框架之一——Volley库中使用。


中断是否会抛出InterruptedException? - Amer Qarabsa
1
它不会抛出InterruptedException,中断的主要用途是调用该线程中的另一个布尔标志;明确地说,if (Thread.interrupted()) {throw new InterruptedException();}这个好例子就是sleep(n)。中断是那个标志的一种特殊触发器。 - Enzokie
你能否编辑你的回答并感谢澄清。 - Amer Qarabsa
1
代码中没有循环...因此无法检查是否被中断标志打断。 - shirish sahu
@Enzokie 如果你把if (Thread.interrupted()) { // 在这里添加你的代码 }放在try块内,那么示例会更清晰、更有信息量。在你当前的代码中,interrupt()是无效的,因为它不能停止任何东西。 - supernova
@supernova 是的,你说得对,但是在回答时我只考虑了OP的情况,在他的代码中,他有 PdfToDocConversion#convertDocToPdf() 这个方法会抛出 InterruptedException,所以我猜测 convertDocToPdf() 方法内部有一个内置的 if (Thread.interrupted()),尽管OP没有添加这个方法的确切代码,所以我也停止重构我的答案,这也是我在代码中使用 try-catch 的原因。 - Enzokie

3

Thread.interrupt()仅在线程对象中设置一个标志,表示该线程应该被中断。它不会导致目标线程抛出InterruptedException异常,相反,可中断的代码必须不断检查该标志,以查看是否有人请求中断。那段代码然后必须处理它,通常通过抛出InterruptedException


代码中没有循环...因此无法检查中断标志。 - shirish sahu
1
@shirishsahu 不需要使用循环来检查中断标志。只需在任务可以被中断的点处检查它即可。 - Smith_61

1
一些答案提到使用volatile boolean isRunning来停止循环,但我在你的示例中没有看到任何循环。中断线程并不会立即中断它,而只是表示“线程将在有机会时被中断”。在您的情况下,建议关闭PDF文件并使用某个布尔标志标记它-然后您可以捕获IOException,如果设置了标志,则意味着您引起了此情况,并且可以完成线程。

实际上,并没有所谓的立即中断。“立即”需要一些周期。 - Enzokie
谢谢Wojciech Kazior,是的,代码中没有循环...所以无法检查中断标志...但线程从未被中断...并且最终该线程会继续利用CPU和内存,并使应用程序停止。 - shirish sahu
@shirishsahu 尝试关闭您的文件连接并捕获IOException。如果有帮助,请接受我的答案,干杯! - Wojciech Kazior

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接