4

我正在尝试用 Java 编写我的第一个多线程程序。我不明白为什么我们需要围绕 for 循环进行这种异常处理。当我在没有 try/catch 子句的情况下编译时,它会给出一个InterruptedException.

这是消息:

Exception in thread "main" java.lang.Error: Unresolved compilation problem: 
Unhandled exception type InterruptedException

但是当使用 try/catch 运行时,catch 块中的 sysout 永远不会显示 - 这意味着无论如何都没有捕获到这样的异常!

public class SecondThread implements Runnable {
    Thread t;
    
    SecondThread() {
        t = new Thread(this, "Thread 2");
        t.start();
    }

    public void run() {
        try {
            for (int i=5; i>0; i--) {
                System.out.println("thread 2: " + i);
                Thread.sleep(1000);
            }
        }
        catch (InterruptedException e) {
            System.out.println("thread 2 interrupted");
        }
    }
}

public class MainThread {

    public static void main(String[] args) {
        new SecondThread();
    
        try {
            for (int i=5; i>0; i--) {
                System.out.println("main thread: " + i);
                Thread.sleep(2000);
            }
        }
        catch (InterruptedException e) {
            System.out.println("main thread interrupted");
        }
    }
}
4

4 回答 4

7

如果 Thread.sleep 方法检测到当前线程设置了其中断标志,则方法 Thread.sleep 抛出 InterruptedException,提前从睡眠中唤醒并允许您使用异常将控制重新定位到当前流之外的某个位置。只有在线程上调用中断时才会设置该标志。

由于您的程序不会在任何线程上调用中断,因此当您运行该程序时不会抛出 InterruptedException。编译器仍然要求您捕获异常,因为它是在 sleep 方法上声明的检查异常。

如果您将这样的方法添加到 SecondThread

public void cancel() {
    t.interrupt();
}

然后在 main 方法中调用 cancel,如下所示:

public static void main(String[] args){
    SecondThread secondThread =  new SecondThread();

    try{
        for(int i=5 ; i>0 ; i--){
            System.out.println("main thread: " + i);
            Thread.sleep(2000);
            secondThread.cancel();
        }
    }
    catch(InterruptedException e){
        System.out.println("main thread interrupted");
    }
}

您将看到在 SecondThread 的 run 方法中捕获 InterruptedException 的 println。

编译错误显示在 Eclipse 中的 Problems 选项卡下,除了在编辑器中通过红色下划线标出外,它们还会在您编辑代码时显示。当您运行此程序时,任何异常都会连同程序输出一起写入控制台。

于 2016-06-02T14:09:55.220 回答
0

您必须InterruptedException在线程中进行处理,因为您正在调用 throw 的方法InterruptedException,而 Java 的设计使您始终必须处理已检查的异常。那就是“在一个线程中”是无关紧要的。

正如它在JLS Sec 11.2中所说:

Java 编程语言要求程序包含检查异常的处理程序,这些异常可能由方法或构造函数的执行引起(第 8.4.6 节、第 8.8.5 节)。

这些处理程序可以是try/catch (InterruptedException)throws InterruptedException; 但是,您不能使用后者,因为 的方法签名void run()不允许您添加已检查异常。

因此,您必须使用 try/catch。

于 2016-06-02T14:20:41.683 回答
0

当我在没有 try/catch 子句的情况下进行编译时,它会给出一个 InterruptedException。

异常是在运行时抛出的,而不是在编译时抛出的,所以这不可能是真的!

可能你得到的编译错误是Thread.sleepcan throw InterruptedException,但是SecondThread.run,从它Thread.sleep被调用,并没有声明它可以抛出它。因此编译器失败,因为异常不能去任何地方。

通常有两种方法可以解决这个问题:

  • 捕获异常,或
  • 在您的方法中添加一个throws子句。

在这种情况下后者是不可能的,因为SecondThread.run覆盖 from Runnable.run,它没有声明它抛出任何异常。所以你需要捕获异常。

如果不是这种情况,或者您的意思是“在没有 try/catch 子句的情况下编译后运行时,它会给出一个 InterruptedException。”,请包括您收到的确切错误消息。实际上,在这里提问时,您应该始终这样做。

于 2016-06-02T14:18:14.607 回答
0

InterruptedException 是一个检查异常,必须被捕获。在您的代码中,它是由睡眠方法引发的。所以如果你不包装它或重新抛出编译器将停止,因为它是一个检查异常。

但是在您的示例程序中,它永远不会在正常情况下被抛出,因为您不会中断。但是,它可以确保当线程处于休眠、等待或处于“僵尸”状态时设置了中断标志并因此被代码或操作系统级别中断时有处理代码称呼。

所以它实际上是需要捕获的,并且它有有效的用途。

于 2016-06-02T14:13:56.117 回答