简体   繁体   English

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

[英]Java Thread: Run method cannot throw checked exception

In Java thread, the 'run' method cannot throw a 'checked exception'. 在Java线程中,'run'方法不能抛出'checked exception'。 I came across this in the Core Java (vol 1) book. 我在Core Java(第1卷)一书中遇到过这个问题。 Can someone please explain the reasoning behind it? 有人可以解释背后的原因吗?

Can someone please explain the reasoning behind it? 有人可以解释背后的原因吗?

Yes, because any exception you throw in run method will be carefully ignored by JVM. 是的,因为JVM会小心忽略您在run方法中抛出的任何异常。 Thus, throwing it there is probably a mistake (unless you have specific exception handler for the thread, see the docs about that). 因此,抛出它可能是一个错误(除非你有线程的特定异常处理程序,请参阅有关该文档的文档 )。 No reason to incite potentially erroneous behaviour. 没有理由煽动潜在的错误行为。

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? 为什么父线程不能从生成的'子'线程'捕获'异常?

@chaotic3quilibrium has 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?

What would catch the exception and handle it? 什么会捕获异常并处理它? Let's assume that the run method could throw a checked exception. 我们假设run方法可以抛出一个已检查的异常。 Then you could write code like this: 然后你可以写这样的代码:

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. 但是一旦你调用myThread.start ,新的线程就会在后台启动,当前线程会继续并退出try-catch并执行其他操作。 So if myThread did throw an exception later on, you can't catch it! 所以如果myThread确实抛出异常,你就无法抓住它!

What you need to do is deal with the exception within the run method and then probably have a way of notifying another object that this thread failed. 您需要做的是在run方法中处理异常,然后可能有办法通知另一个对象该线程失败。

Suppose thread A starts up thread B. Then thread B throws an exception. 假设线程A启动线程B.然后线程B抛出异常。 You might think it would be nice for thread A to catch it. 您可能认为线程A捕获它会很好。 But where? 但是哪里? By the time thread B thows the exception, who knows what thread A is doing? 当线程B抛出异常时,谁知道线程A正在做什么? To take a trivial example, suppose we have this code in thread 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. 所以我们启动线程B来清除废弃的推车。 Once it gets starte, we move on to processing new orders. 一旦它开始,我们继续处理新订单。 Then thread B throws a null pointer exception. 然后线程B抛出空指针异常。 Should it be caught by the catch block associated with thread B, or the one associated with processing new orders? 它是否应该被与线程B关联的catch块或与处理新订单相关联的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. 如果它转到新订单catch,那么这里的任何代码都可能与清除线程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. 如果你说与线程B相关联的那个,那么这意味着在处理新订单期间,控制可能突然被拉出并发送回尝试线程B catch块。 But then what happenned to processing new orders? 但接下来处理新订单会发生什么? Do we just stop in the middle? 我们只是停在中间吗? Do we not even hit the finally block? 我们甚至没有击中finally块? 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. 这也不是正确的答案。

Thus, there is nowhere to go if run throws an exception. 因此,如果run抛出异常,那就无处可去。 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方法捕获自己抛出的任何异常,并在新线程中处理它们。

throws declarations are part of the methods signature. throws声明是方法签名的一部分。 To allow checked exceptions for Runnable#run , one had to declare them on the Runnable interface and had to try/catch everytime we start a thread. 要允许Runnable#run检查异常,必须在Runnable接口上声明它们,并且每次启动线程时都必须try/catch

Then again, we usually don't call the run method, we just implement it. 然后,我们通常不会调用run方法,我们只是实现它。 We start() a Thread and then, somehow, the run method is called. 我们start()一个Thread,然后以某种方式调用run方法。

But the most obvious reason: When we start threads, we usually don't want to wait until the run method terminates just to catch exceptions like this: 但最明显的原因是:当我们启动线程时,我们通常不希望等到run方法终止只是为了捕获这样的异常:

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

The reason is that exception is thrown back to the caller. 原因是异常被抛回调用者。 Caller of run() method is not your code. run()方法的调用者不是您的代码。 It is the Thred itself. 这是Thred本身。 So even if run() throws exception the program cannot catch it. 因此,即使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:executors和interface Callable声明方法call(),它返回线程执行的未来结果。

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. 之前答案的更明显的解决方案是,如果抛出一个已检查的异常,则表示您未正确实现runnable接口中指定的run()。

It won't even compile: 它甚至不会编译:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如果方法无法引发声明的已检查异常,则配置Java编译器是否出错 - Configure Java Compiler for Error if method cannot throw declared checked Exception 如何从 Java 线程抛出已检查的异常? - How to throw a checked exception from a java thread? 使用 Java 可选 ifPresentOrElse 方法时无法抛出 `checked` 异常 - Unable to throw a `checked` exception when using Java Optional ifPresentOrElse method Java:向另一个Thread抛出异常 - Java: Throw an exception to another Thread “专门化”一个子类型的方法来抛出一个已检查的异常? - “Specializing” a subtype's method to throw a checked exception? 为什么runnable run()不能抛出已检查的异常? - Why cannot run() of Runnable throw checked Exceptions? Java检查异常不在函数的throw规范中? - Java checked exception not in the function's throw specification? 在java中将已检查的异常抛出为未检查而不是包装 - throw checked exception as unchecked in java instead of wrapping jaxws 和 apache cxf 和 glassfish 5 错误:java.lang.IllegalStateException:生命周期方法 [finalizeConfig] 不能抛出已检查的异常 - jaxws and apache cxf and glassfish 5 error: java.lang.IllegalStateException: The lifecycle method [finalizeConfig] must not throw a checked exception Java在类方法上引发异常 - Java throw exception at class method
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM