如何从java线程抛出一个检查exception?

嘿,我正在写一个networking应用程序,在这个应用程序中我读取了一些自定义二进制格式的数据包 我开始后台线程来等待传入的数据。 问题是,编译器不让我把任何代码抛出(检查)exception到run() 。 它说:

  run()in(...)。Listener不能在java.lang.Runnable中实现run(); 重写的方法不会抛出java.io.IOException 

我想要exception杀死线程,并让它在父线程的某处被捕获。 这是可能实现或我必须处理线程的每个exception?

警告:如果您必须使用exception机制,这可能不符合您的需求。

如果我正确地理解了你,你实际上并不需要检查exception(你已经接受了提示一个未经检查的exception的答案),那么一个简单的监听模式会更合适吗?

监听器可以存在于父线程中,当你在子线程中检测到exception时,你可以直接通知监听器。

这意味着你有一种公开的方式,这将会发生(通过公共方法),并将能够传递更多的信息,而不是一个例外允许的。 但是这意味着在父子线程之间会有一个耦合(虽然是松散的)。 这将取决于你的具体情况,这是否有利于包装检查的exception与未选中的一个。

这里有一个简单的例子(从另一个答案中借用的一些代码):

 public class ThingRunnable implements Runnable { private SomeListenerType listener; // assign listener somewhere public void run() { try { while(iHaveMorePackets()) { doStuffWithPacket(); } } catch(Exception e) { listener.notifyThatDarnedExceptionHappened(...); } } } 

耦合来自父线程中的对象,必须是SomeListenerTypetypes的SomeListenerType

为了能够将exception发送到父线程,可以将后台线程放在Callable (允许抛出exception),然后将其传递给某个Executor的提交方法。 提交方法将返回一个Future ,然后您可以使用它来获取该exception(其get方法将抛出包含原始exception的ExecutionException )。

这个答案是基于Esko Luontola一个,但它提供了一个工作的例子。

与Runnable接口的run()方法不同,Callable的call()方法允许抛出一些exception。 这里是一个实现的例子:

 public class MyTask implements Callable<Integer> { private int numerator; private int denominator; public MyTask(int n, int d) { this.numerator = n; this.denominator = d; } @Override // The call method may throw an exception public Integer call() throws Exception { Thread.sleep(1000); if (denominator == 0) { throw new Exception("cannot devide by zero"); } else { return numerator / denominator; } } } 

Executor提供了一种机制来在线程中运行Callable并处理任何types的exception:

 public class Main { public static void main(String[] args) { // Build a task and an executor MyTask task = new MyTask(2, 0); ExecutorService threadExecutor = Executors.newSingleThreadExecutor(); try { // Start task on another thread Future<Integer> futureResult = threadExecutor.submit(task); // While task is running you can do asynchronous operations System.out.println("Something that doesn't need the tasks result"); // Now wait until the result is available int result = futureResult.get(); System.out.println("The result is " + result); } catch (ExecutionException e) { // Handle the exception thrown by the child thread if (e.getMessage().contains("cannot devide by zero")) System.out.println("error in child thread caused by zero division"); } catch (InterruptedException e) { // This exception is thrown if the child thread is interrupted. e.printStackTrace(); } } } 

我所做的就是在线程中捕获exception,并将其作为Runnable的成员variables进行存储。 这个exception然后通过Runnable上的getter来暴露。 然后,我扫描父级的所有线程,看是否有exception,并采取适当的行动。

该线程不能将该exception抛出到任何其他线程(或主线程)。 你不能让inheritance的run()方法抛出任何检查的exception,因为你只能抛出比inheritance的代码less的东西,而不是更多。

如果在引发exception时确实无法做任何有用的事情,则可以将检查的exception封装在RuntimeException中。

 try { // stuff } catch (CheckedException yourCheckedException) { throw new RuntimeException("Something to explain what is happening", yourCheckedException); } 

如果你的线程的代码抛出一个RuntimeExpection,你不需要添加run()抛出Exception。

但只有在适当的时候才使用这个解决scheme,因为这可能是一个不好的实践: http : //java.sun.com/docs/books/tutorial/essential/exceptions/runtime.html

任何RuntimeException或未经检查的Exception都可以帮助你。 也许你需要创build你自己的RuntimeException

假设你的代码在某种循环中,你可以这样写:

 public class ThingRunnable implements Runnable { public void run() { try { while(iHaveMorePackets()) { doStuffWithPacket() } } catch(Exception e) { System.out.println("Runnable terminating with exception" + e ); } } } 

exception会自动将您从循环中分离出来,并且在run()方法结束时,线程将停止。

RuntimeException包装你的exception似乎有诀窍。

 someMethod() throws IOException { try { new Thread(() -> { try { throw new IOException("a checked exception thrown from within a running thread"); } catch(IOException ex) { throw new RuntimeException("a wrapper exception", ex); // wrap the checked exception inside an unchecked exception and throw it } }).start(); } catch(RuntimeException ex) // catch the wrapped exception sent from within the thread { if(ex.getCause() instanceof IOException) throw ex.getCause; // unwrap the checked exception using getCause method and use it however you need else throw ex; } }