简体   繁体   English

如何使从线程引发的未经检查的异常传播到主线程?

[英]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.

相关问题 在Java中,如何捕获从子线程引发的异常,然后从父线程再次引发异常 - In java how can I catch an exception thrown from child thread and then throw it again from the parent thread 在其他线程中抛出异常会导致主线程崩溃吗? - Will an exception thrown in a Different thread will crash the main thread? 如何在java中将主线程作为守护线程? - How can i make the main Thread as Daemon Thread in java? 如何从单独的线程暂停主线程? - How can I pause Main thread from a separate thread? 如何从Thread.currentThread()获取主线程? - How can I get Main Thread from Thread.currentThread()? 在Eclipse中引发未经检查的异常时,从新创建的线程打印堆栈跟踪 - Printing the stack trace from a newly created thread when an unchecked exception is thrown in Eclipse 在主线程中抛出异常时停止后台线程 - Stop background thread when exception is thrown in main thread 我如何解决线程“ main”中的异常java.lang.NoSuchMethodError:main - How can i resolve the Exception in thread “main” java.lang.NoSuchMethodError: main 如何在Java应用程序中从Main方法运行线程? - How can I run thread from Main method in Java application? 处理线程池中可调用对象引发的异常 - Handling Exception thrown by a Callable from a Thread Pool
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM