[英]How can I make an unchecked exception thrown from a thread to be propagated to main thread?
I can't find a way (neither through SO nor debugging my code) to allow an exception thrown from a tread to be propagated to the main thread. 我找不到一种方法(既不能通过SO也不能调试我的代码)来允许将从胎面引发的异常传播到主线程。 I have already tried using Thread.setUncaughtExceptionHandler()
and using CompletableFuture
: .exceptionally()
, .handle()
,... 我已经尝试使用Thread.setUncaughtExceptionHandler()
和CompletableFuture
: .exceptionally()
.handle()
,...
The point is that with these mechanisms (as I debug), the actual handling is performed on the worker thread, not main thread -and I cannot manage to get it to to the main thread. 关键是,使用这些机制(在我调试的时候),实际的处理是在工作线程上执行的,而不是在主线程上执行的-我无法设法将其到达主线程。
The overall point is that I'm writing a test and that if the exception raises in the worker thread, it never gets to the main thread where the test is running, making the test to pass even when something went wrong. 总的来说,我正在编写一个测试,并且如果在工作线程中引发异常,则它永远不会到达运行测试的主线程,即使出现问题也可以使测试通过。
I would need that exception would raise asynchronous; 我需要该异常会引发异步; I cannot wait for the future to complete as I need to immediately return a Stream (a PipedStream) without blocking, from the main tread. 我不能等待将来完成,因为我需要立即从主界面立即返回一个Stream(PipedStream)而不发生阻塞。
The only tip I get is a console error (and only when I use the traditional Thread
+ uncaughtExceptionHandler
approach, no log at all when I try with CompletableFuture
): 我得到的唯一提示是控制台错误(并且仅当我使用传统的Thread
+ uncaughtExceptionHandler
方法时,当我尝试使用CompletableFuture
时根本没有日志):
Exception: com.example.exception.MyException thrown from the UncaughtExceptionHandler in thread "Thread-5"
or this if I don't define the exception handler: 如果我没有定义异常处理程序,则为:
Exception in thread "Thread-5" com.example.MyException: Exception message
I provide some code: 我提供一些代码:
try {
@SuppressWarnings("squid:S2095") final PipedOutputStream pos = new PipedOutputStream();
final PipedInputStream pis = new PipedInputStream(pos);
CompletableFuture.runAsync(pipeDecryptorRunnable(inputStream, pos));
return pis;
} catch (IOException e) {
throw new CryptographyException(e.getMessage(), e);
}
Inside pipeDecryptorRunnable
is a CipherStream that decrypts data. 在pipeDecryptorRunnable
内部是一个解密数据的CipherStream。 The exception is thrown there. 那里抛出异常。 But I cannot catch it in the main thread and becomes invisible. 但是我无法在主线程中将其捕获并变得不可见。 The pis
stream returning from this method is used to read and worker thread decrypts data on-the-fly as its being read prom pis
. 从此方法返回的pis
流用于读取,并且工作线程在读取prom pis
实时解密数据。
EDIT: UncaughtExceptionHandler
as the answers in similar questions suggests does not work for my scenario as the handler code is invoked by worker thread, not the main one. 编辑: UncaughtExceptionHandler
作为类似问题的答案表明不适用于我的情况,因为处理程序代码是由工作线程而不是主线程调用的。
Thanks to the tip of @RalfKleberhoff I came with the solution I was looking for. 感谢@RalfKleberhoff的技巧,我提供了我所寻找的解决方案。 The fact is that to achieve the desired behavior an inter thread communication mechanism is required. 事实是,为了实现所需的行为,需要线程间通信机制。 And given that I were already working with a PipedStream
s, I can leverage it to accomplish the goal –I also thought in some kind of solution involving an event bus to signal or communicate from one thread to another (main thread/worker thread) and I think some event bus libraries can achieve it as well. 考虑到我已经在使用PipedStream
,我可以利用它来实现目标–我还认为,在某种解决方案中,涉及事件总线来从一个线程向另一个线程(主线程/工作线程)发出信号或进行通信,我认为某些事件总线库也可以实现它。
So back to piped streams I had a pis
to read in the main thread and its connected pos
to write in the worker thread. 回到管道流中,我需要在主线程中读取pis
并在工作线程中写入其连接的pos
。 So that, when an exception was raised in the worker, I need the main thread to notice that. 因此,当在worker中引发异常时,我需要主线程来注意到这一点。
To achieve that you can extend the PipedOutputStream
class, adding a method to signal the connected pipe when an exception occurs. 为此,您可以扩展PipedOutputStream
类,添加一个方法以在发生异常时向连接的管道发出信号。 The same way, you need to extend the connected PipedInputStream
to be signaled on exception, store the exception and override the read methods in order to check if an exception occurred first and, in that case, throw the exception wrapped in the IOException
of the read method. 同样,您需要扩展连接的PipedInputStream
以在发生异常时发出信号,存储异常并覆盖read方法,以检查是否首先发生异常,在这种情况下,将异常包装在读取的IOException
中方法。
Here the code: 这里的代码:
/**
* This piped stream class allows to signal Exception between threads, allowing an exception produced in the writing
* thread to reach the reading thread.
*
* @author Gerard on 10/11/2017.
*/
public class ExceptionAwarePipedOutputStream extends PipedOutputStream {
private final ExceptionAwarePipedInputStream sink;
public ExceptionAwarePipedOutputStream(ExceptionAwarePipedInputStream sink) throws IOException {
super(sink);
this.sink = sink;
}
/**
* Signals connected {@link ExceptionAwarePipedInputStream} that an exception ocurred allowing to propagate it
* across respective threads. This works as inter thread communication mechanism. So it allows to the reading thread
* notice that an exception was thrown in the writing thread.
*
* @param exception The exception to propagate.
*/
public void signalException(Throwable exception) {
sink.signalException(exception);
}
}
· ·
/**
* This piped stream class allows to signal Exception between threads, allowing an exception produced in the writing
* thread to reach the reading thread.
*
* @author Gerard on 10/11/2017.
*/
public class ExceptionAwarePipedInputStream extends PipedInputStream {
private volatile Throwable exception;
void signalException(Throwable exception) {
this.exception = exception;
}
@Override
public int read(byte[] b) throws IOException {
final int read = super.read(b);
checkException();
return read;
}
@Override
public synchronized int read() throws IOException {
final int read = super.read();
checkException();
return read;
}
@Override
public synchronized int read(byte[] b, int off, int len) throws IOException {
final int read = super.read(b, off, len);
checkException();
return read;
}
private void checkException() throws IOException {
if (exception != null) {
throw new IOException(exception.getMessage(), exception);
}
}
}
The client code: 客户端代码:
public InputStream decrypt(InputStream inputStream) {
assert supportedStreamModes.contains(mode) : "Unsupported cipher mode for stream decryption " + mode;
@SuppressWarnings("squid:S2095") final ExceptionAwarePipedInputStream pis = new ExceptionAwarePipedInputStream();
final ExceptionAwarePipedOutputStream pos = newConnectedPipedOutputStream(pis);
final Cipher decryptor = newDecryptorInitialized(inputStream);
CompletableFuture.runAsync(
pipeDecryptorRunnable(inputStream, pos, decryptor));
return pis;
}
private ExceptionAwarePipedOutputStream newConnectedPipedOutputStream(ExceptionAwarePipedInputStream pis) {
try {
return new ExceptionAwarePipedOutputStream(pis);
} catch (IOException e) {
throw new CryptographyException(e.getMessage(), e);
}
}
And the exception handling part ( notice the thread signaling): 和异常处理部分( 注意线程信令):
private Runnable pipeDecryptorRunnable(InputStream inputStream, ExceptionAwarePipedOutputStream pos, Cipher decryptor) {
return () -> {
try {
// do stuff... and write to pos
} catch (Exception e) {
// Signaling any (checked or unchecked) exception
pos.signalException(new CryptographyException(e.getMessage(), e));
} finally {
closePipedStream(pos);
}
};
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.