为啥我必须将每个 Thread.sleep() 调用包装在 try/catch 语句中? [复制]

Posted

技术标签:

【中文标题】为啥我必须将每个 Thread.sleep() 调用包装在 try/catch 语句中? [复制]【英文标题】:Why must I wrap every Thread.sleep() call in a try/catch statement? [duplicate]为什么我必须将每个 Thread.sleep() 调用包装在 try/catch 语句中? [复制] 【发布时间】:2016-10-02 07:58:08 【问题描述】:

我正在尝试用 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");
        
    

【问题讨论】:

When I compile without the try/catch clauses it gives an InterruptedException: 不,它没有,它给出了一个错误,你没有捕捉到检查的异常——这与编译器给你一个异常是非常不同的。 当我编译时,它说:线程“main”java.lang.Error中的异常:未解决的编译问题:未处理的异常类型InterruptedException at MainThread.main(MainThread.java:10) @SergioGliesh:edit你的问题,不要写在评论里。 如果你不想处理InterruptedException,一种选择是使用Guava的Uninterruptibles.sleepUninterruptibly(),它可以适当地抑制InterruptedException,但是(顾名思义)意味着你不能更长的时间打断睡眠,这通常不是你真正想做的。 【参考方案1】:

如果 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 选项卡下,除了在编辑器中通过红色下划线标出之外,它们还会在您编辑代码时显示。当您运行此程序时,任何异常都会连同程序输出一起写入控制台。

【讨论】:

【参考方案2】:

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

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

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

【讨论】:

【参考方案3】:

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

正如JLS Sec 11.2中所说:

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

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

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

【讨论】:

【参考方案4】:

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

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

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

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

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

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

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

【讨论】:

我什至不知道如何在 Eclipse 中识别编译时错误和运行时错误!无论如何,这就是所说的:线程“主”java.lang.Error中的异常:未解决的编译问题:未处理的异常类型InterruptedException at MainThread.main(MainThread.java:10) 如果在编译时发生:这是编译时错误。如果在代码运行时发生:这是运行时错误。提示:当它说“未解决的编译问题”时,这是一个编译时错误。

以上是关于为啥我必须将每个 Thread.sleep() 调用包装在 try/catch 语句中? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

为啥 Thread.Sleep 如此有害

如果 Task.Delay 优于 Thread.Sleep,为啥本书中的示例使用 Thread.Sleep?

为啥 Thread.sleep 不好用

替代 Thread.Sleep

为啥 Thread.Sleep 不在秒表中注册?

为啥 thread.sleep 在第一次捕获时不停止?