Java 线程:Run 方法不能抛出已检查的异常

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/4491606/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-14 18:00:40  来源:igfitidea点击:

Java Thread: Run method cannot throw checked exception

javamultithreadingexception

提问by Neel

In Java thread, the 'run' method cannot throw a 'checked exception'. I came across this in the Core Java (vol 1) book. Can someone please explain the reasoning behind it?

在 Java 线程中,“run”方法不能抛出“checked exception”。我在 Core Java (vol 1) 一书中遇到了这个问题。有人可以解释一下背后的原因吗?

采纳答案by Nikita Rybak

Can someone please explain the reasoning behind it?

有人可以解释一下背后的原因吗?

Yes, because any exception you throw in runmethod will be carefully ignored by JVM. Thus, throwing it there is probably a mistake (unless you have specific exception handler for the thread, see the docsabout that). No reason to incite potentially erroneous behaviour.

是的,因为您在run方法中抛出的任何异常都会被 JVM 小心地忽略。因此,抛出它可能是一个错误(除非您有线程的特定异常处理程序,请参阅有关此的文档)。没有理由煽动潜在的错误行为。

Or, with an example.

或者,举个例子。

 class MyThread extends Thread {
     public void run() {
         throw new RuntimeException();
     }
 }

...

new MyThread().start();
// here thread dies silently with no visible effects at all

edit

编辑

Why can't the parent thread 'catch' the exception from the spawned 'child' thread?

为什么父线程不能从生成的“子”线程“捕获”异常?

@chaotic3quilibriumhas already noted in his comment why not: because parent thread has likely moved on already.

@chaotic3quilibrium已经在他的评论中指出了为什么不这样做:因为父线程可能已经开始了。

new MyThread().start(); // launch thread and forget

// 1000 lines of code further...
i = i + 1; // would you like exception from child thread to be propagated here?

回答by Andreas Dolk

throwsdeclarations are part of the methods signature. To allow checked exceptions for Runnable#run, one had to declare them on the Runnableinterface and had to try/catcheverytime we start a thread.

throws声明是方法签名的一部分。为了允许检查异常Runnable#run,必须在Runnable接口上声明它们,并且try/catch每次启动线程时都必须声明。

Then again, we usually don't call the runmethod, we just implement it. We start()a Thread and then, somehow, the runmethod is called.

再说一次,我们通常不调用run方法,我们只是实现它。我们创建start()了一个线程,然后以某种方式run调用了该方法。

But the most obvious reason: When we start threads, we usually don't want to wait until the runmethod terminates just to catch exceptions like this:

但最明显的原因是:当我们启动线程时,我们通常不想等到run方法终止才捕获这样的异常:

try {
   new Worker().start();  // now wait until run has finished
} catch (SomeThreadException oops) {
   // handle checked exception
}

回答by AlexR

The reason is that exception is thrown back to the caller. Caller of run() method is not your code. It is the Thred itself. So even if run() throws exception the program cannot catch it.

原因是异常被抛回给调用者。run() 方法的调用者不是您的代码。它是 Thred 本身。因此,即使 run() 抛出异常,程序也无法捕获它。

You should put thread execution result to some class level variable and then read it from there. Or alternatively use new API: executors and interface Callable that declares method call() that returns future result of the thread execution.

您应该将线程执行结果放到某个类级别的变量中,然后从那里读取它。或者使用新的 API:执行器和接口 Callable 声明方法 call() 返回线程执行的未来结果。

回答by dogbane

What would catch the exception and handle it? Let's assume that the run method could throw a checked exception. Then you could write code like this:

什么会捕获异常并处理它?让我们假设 run 方法可以抛出一个已检查的异常。然后你可以写这样的代码:

Thread myThread = new Thread(aRunnable);
try{
    myThread.start();
}
catch(Exception e){
   e.printStackTrace();
}
//do other stuff

BUT once you call myThread.start, the new thread is started in the background and the current thread continues and exits the try-catch and does other stuff. So if myThreaddid throw an exception later on, you can't catch it!

但是一旦你调用myThread.start,新线程在后台启动,当前线程继续并退出 try-catch 并执行其他操作。因此,如果myThread稍后确实抛出异常,您将无法捕获它!

What you need to do is deal with the exception within the runmethod and then probably have a way of notifying another object that this thread failed.

您需要做的是处理run方法内的异常,然后可能有一种方法通知另一个对象此线程失败。

回答by Benjamin Wootton

The more obvious solution to the previous answers is that if you throw a checked exception, you are not correctly implementing run() as specified in the runnable interface.

前面答案的更明显的解决方案是,如果您抛出已检查的异常,则您没有按照可运行接口中的指定正确实现 run()。

It won't even compile:

它甚至不会编译:

run() in TestClass cannot implement run() in java.lang.Runnable; 
overridden method does not throw java.lang.Exception  

回答by Jay

Suppose thread A starts up thread B. Then thread B throws an exception. You might think it would be nice for thread A to catch it. But where? By the time thread B thows the exception, who knows what thread A is doing? To take a trivial example, suppose we have this code in thread A:

假设线程 A 启动线程 B。然后线程 B 抛出异常。您可能认为线程 A 捕获它会很好。但是哪里?到线程 B 抛出异常时,谁知道线程 A 在做什么?举一个简单的例子,假设我们在线程 A 中有以下代码:

try
{
  threadB=new PurgeAbandonedCarts();
  threadB.start();
}
catch (NullPointerException panic)
{
  ... handle errors purging abandoned carts ...
}
try
{
  processNewOrders();
}
catch (NullPointerException panic)
{
  ... handle problems in new orders ...
}
finally
{
  ... clean up ...
}

So we start up thread B to purge abandoned carts. Once it gets starte, we move on to processing new orders. Then thread B throws a null pointer exception. Should it be caught by the catch block associated with thread B, or the one associated with processing new orders?

所以我们启动线程 B 来清除废弃的购物车。一旦开始,我们将继续处理新订单。然后线程 B 抛出空指针异常。它应该被与线程 B 关联的 catch 块捕获,还是由与处理新订单关联的那个块捕获?

If it goes to the new orders catch, it's likely that any code here has nothing to do with cleaning up problems with thread B. That can't be the right answer.

如果涉及到新的订单捕获,很可能这里的任何代码都与清理线程 B 的问题无关。这不是正确的答案。

If you say the one associated with thread B, then that means that during the processing of new orders, control could suddenly be yanked out and sent back to try thread B catch block. But then what happenned to processing new orders? Do we just stop in the middle? Do we not even hit the finally block? And when we're done, do we then just keep executing and fall through to processing new orders again? Do we process orders twice? This can't be the right answer either.

如果您说与线程 B 关联的那个,那么这意味着在处理新订单期间,控制权可能会突然被拉出并发送回 try 线程 B 的 catch 块。但是,处理新订单时发生了什么?我们只是停在中间吗?我们甚至没有碰到 finally 块吗?当我们完成后,我们是否继续执行并再次处理新订单?我们处理订单两次吗?这也不能是正确答案。

Thus, there is nowhere to go if run throws an exception. The only logical thing to do is to have the run method catch any exceptions thrown itself, and handle them within the new thread.

因此,如果 run 抛出异常,则无处可去。唯一合乎逻辑的做法是让 run 方法捕获自己抛出的任何异常,并在新线程中处理它们。