为什么我必须在try / catch语句中包装每个Thread.sleep()调用?

时间:2016-06-02 14:07:01

标签: java interrupted-exception interruption

我正在尝试用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 个答案:

答案 0 :(得分:5)

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中显示,除了通过红色下划线在编辑器中调出外,它们会在您编辑代码时显示出来。运行此程序时,任何异常都将与程序输出一起写入控制台。

答案 1 :(得分:0)

InterruptedException是一个已检查的异常,必须被捕获。在你的代码中,它被sleep-method抛出。因此,如果您不包装它或重新抛出,编译器将停止,因为它是一个已检查的异常。

但是在你的示例程序中,它不会在正常情况下被抛出,因为你不会中断。但是,它确保有一个处理代码,用于处理正在休眠,等待或者在" zombie" -state中的线程设置了中断标志并因此被代码中断的处理代码或通过操作系统级别的呼叫。

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

答案 2 :(得分:0)

  

当我在没有try / catch子句的情况下编译时,它会产生InterruptedException。

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

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

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

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

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

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

答案 3 :(得分:0)

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

正如JLS Sec 11.2中所述:

  

Java编程语言要求程序包含检查异常的处理程序,这些处理程序可能是由于执行方法或构造函数而导致的(§8.4.6,§8.8.5)。

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

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