【问题标题】:Java: Daemon: thread.join() not finishing, when Exception was thrown before in one threadJava:守护进程:thread.join() 未完成,之前在一个线程中抛出异常
【发布时间】:2012-06-04 15:36:42
【问题描述】:

我写了一个 Java Daemon(一个实现 Daemon 和 Runnable 的类),现在我面临以下问题:

在 init() 中我创建了一个新线程。 Thread thread = new Thread(this); 在 start() 中,我启动了新线程。 thread.start()。 在运行中我做了很多不同的事情......然后发生异常。 (在我的例子中:NullPointerException。)。

现在发生的事情是我在 run() 中捕获了异常并调用了 stop()。在那里我调用thread.join(),但这永远不会结束并且不会抛出 InterruptedException。我该如何解决这个问题?

在 run() 中,我在 while 循环中做一些事情

private Thread thread;

public void init() {
    // if init is successful: this.thread = new Thread(this);
    // if init is not successful: call stop()
}

public void run() {
  try{
  // do something
  while (!this.stopping)
  {
      // do somthing
  }
  } catch (Exception e) {
      //do something and then call stop()
  }
}

public void stop() {
    this.stopping = true;
    thread.join(); // catch InterruptedException if it did not work
    // do some more things
}

这就是引发异常的地方。停止是不稳定的,一旦调用停止,我就将其设置为 true。

谢谢你:-)


我得到了很多答案,但我仍然没有解决这个问题。每个人都说我不应该在我的 run() 或 init() 方法中手动调用 stop()。我的问题是,当 init() 或 run() 中发生异常时,我真的想要 stop 程序。完成它,使程序不再运行。我不知道如何在不调用 stop() 的情况下实现这一点。简单地等到 run() 完成是行不通的,因为它会停止并且 stop() 永远不会被调用。我还不确定如何处理异常问题。

【问题讨论】:

  • 你能多贴一点代码吗?事实上,我认为你应该尝试对 Callable docs.oracle.com/javase/6/docs/api/java/util/concurrent/… 和 ExecutorService 做同样的事情,因为你会在主线程中收到有关异常的通知。
  • 那么我还能如何停止守护进程?
  • @nano7 -- 从run()返回。
  • 当 init() 被调用并且我在 init() 中做的一些事情失败时 - 我不应该在那里调用 stop() 吗?我应该抛出异常还是直接返回?
  • 嗯。如果我不在 init() 中手动调用 stop(),如果 init() 失败,我将永远无法到达 stop(),因为如果 init() 失败,我不会创建新线程。我应该抛出 DaemonInitException 吗?

标签: java multithreading exception daemon runnable


【解决方案1】:

拨打stop 很好。人们警告你不要打电话给Thread.stop(),你没有这样做。你正在做的是在你想加入的同一个线程上调用join - 这当然会导致死锁。你有

catch (Exception e) {
  //do something and then call stop()
}

这意味着您确实正在run 方法调用stop。那是错误的。它毫无例外地工作,因为那时你没有进入catch-block。您只需在该 catch 块中写入 break; 即可中断 while 循环。

顺便说一句,您根本不需要对Thread 的引用——这只是令人困惑的事情。如果您需要访问您正在执行run 方法的Thread 实例,您可以调用Thread.currentThread()

【讨论】:

  • 感谢您的回答。确实,我不调用thread.stop(),而是调用stop()。 join() 遵循停止某些事情的代码,例如码头服务器和 run() 期间发生的事情所使用的资源。也许你是对的,我不需要它,因为我只有一个线程?
  • 您没有发布代码,所以我只是在猜测。如果您从run 方法调用join,那么这对我来说没有意义。如果你从其他线程调用stop,然后调用join——这确实有意义。
  • 我发布了一些伪代码。也许你现在可以告诉我这是否有意义?我现在遇到的问题:我没有在 run() 中手动调用 stop(),但现在如果 run() 中抛出异常,则不会调用 stop()。而且,如果我不在 init() 中手动调用 stop() 如果 init() 失败,则 stop() 也永远不会到达那里。
  • 感谢您的回答。休息;不起作用,因为 catch 已经在循环之外了。通常它会完成捕获,然后我认为该方法会结束。我想知道为什么不调用 stop() 。我会再试一次。
  • 如果它在循环之外,那么您根本不需要任何东西。你已经跳出了运行循环,你的线程会自然死亡。
【解决方案2】:

你永远不应该叫停。只需从运行返回或从运行抛出异常,线程将自行停止。 Thread.join 意味着从某个想要等待守护线程完成的线程调用。例如,如果主线程收到要关闭的消息,它可能会通知守护进程停止(而不是通过调用 stop),然后使用 join 等待守护进程实际停止。有教程here

【讨论】:

  • 好吧,因为我只有一个线程 (=new Thread(this)) 并且没有为任何线程设置 thread.setDaemon(true),我不需要 thread.join,对吗?我想知道为什么没有抛出异常时它会起作用......
【解决方案3】:

很难确切知道哪里出了问题,因为您的示例仍然只是部分代码。我附上了我能写的最简单的多线程程序。主线程每 100 毫秒打印一次“main”。另一个线程每 100 毫秒打印一次“其他”,直到停止。主线程在 10 次迭代后停止另一个线程。你能解释一下这个程序没有做什么你想让你做的吗?我们可以更改它,直到它这样做为止。

public class Main {

    private Thread thread;
    private Other other;

    public static void main(String args[]) throws InterruptedException {
        Main main = new Main();
        main.run();
    }

    public void run() {
        other = new Other();
        thread = new Thread(other);
        thread.start();
        for (int i = 0; i < 10; i++) {
            System.out.println("main");
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                System.out.println("interrupted waiting for sleep in main");
            }
        }
        stop();
    }

    public void stop() {
        other.stopping = true;
        try {
            thread.join();
        } catch (InterruptedException e) {
            System.out.println("interrupted waiting for other to join main");
        }
    }

}

class Other implements Runnable {

    volatile boolean stopping;

    @Override
    public void run() {
        while (!stopping) {
            System.out.println("other");
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                System.out.println("interrupted waiting for sleep in other");
            }
        }
    }

}

【讨论】:

  • 感谢您的回答!如果 other.run() 抛出 NullPointerException 会发生什么? [我的 other.run() 没有实现 Runnable,但它是一种可以抛出异常的方法] 在我的情况下,stop() 中的 thread.join() 从未返回。我真正想要的是如果 run() 中的异常被抛出(当然只有在 stop() 和 destroy() 被调用之后)关闭整个程序。我试图通过将 thread.join() 设置为线程来修复它。加入(3000)。由于这并没有关闭程序,我现在使用 System.exit(1),它正在工作,但不是很“好”。 :-)
  • 你可以调用Runtime.getRuntime().addShudownHook()。您传递的线程将在调用 exit 后或任何其他预期 VM 将关闭的时间启动。关闭会延迟到线程完成。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-01-11
  • 2018-09-18
  • 2021-09-16
  • 1970-01-01
  • 1970-01-01
  • 2017-12-23
  • 1970-01-01
相关资源
最近更新 更多