java - 将 PipedWriter+PipedReader 对的写入器线程的错误委托(delegate)给读取器线程

标签 java multithreading io pipe

我想要什么?

我有一个 PipedWriter + PipedReader 对,有两个线程。我希望,在写入器线程中捕获的异常将在包装成 IOException 的 PipedReader 的下一个操作中抛出。如果 PipedReader 本身出现错误,则可以将写入器线程异常添加到受抑制的异常中。

为什么?

问题是,如果写入线程中发生错误,我只能关闭写入器,这会导致读取器端出现正常的 EOF。我希望读者线程知道作者方面的错误。但我希望我的代码的用户应该看到一个简单的阅读器。所以我必须将该错误作为 IOException 呈现。

问题

您知道任何类型的开箱即用的“错误委托(delegate)pipedwriter+reader”实现吗?你如何以线程安全的方式实现这样的事情?

最佳答案

解决方案

我创建了一个“ErrorDelegatingReaderDecorator”:

import java.io.IOException;
import java.io.Reader;

class ErrorDelegatingReaderDecorator extends Reader {
    static final String ERROR_MESSAGE_WRITER_THREAD = "Error occoured on the other side of the pipe. See the cause!";
    static final String ERROR_MESSAGE_READER_THREAD = "Error occoured on the this side of the pipe. See the cause!";
    private Reader decorated;
    private Throwable delegatedThrowable;

    public ErrorDelegatingReaderDecorator(Reader decorated) {
        super();
        this.decorated = decorated;
    }

    @Override
    public int read(char[] cbuf, int off, int len) throws IOException {
        Throwable originalException = null;
        int result = -1;
        try {
             result = decorated.read(cbuf, off, len);           
        }
        catch( Throwable original ) {
            originalException = original;
        }
        finally {
            throwException(originalException);
        }
        return result;
    }

    @Override
    public void close() throws IOException {
        Throwable originalException = null;
        try {
            decorated.close();          
        }
        catch( Throwable original ) {
            originalException = original;
        }
        finally {
            throwException(originalException);
        }
    }

    private synchronized void throwException(Throwable originalException) throws IOException {
        Throwable delegatedTemp = delegatedThrowable;
        delegatedThrowable = null;
        if ( originalException != null ) {
            if ( delegatedTemp != null ) {
                originalException.addSuppressed(delegatedTemp);
            }
            throw new IOException( ERROR_MESSAGE_READER_THREAD, originalException ) ;
        }
        else if ( delegatedTemp != null ) {
            throw new IOException( ERROR_MESSAGE_WRITER_THREAD, delegatedTemp );
        }
    }


    public synchronized void setDelegatedThrowable(Throwable delegatedThrowable) {
        this.delegatedThrowable = delegatedThrowable;
    }
}

然后我可以这样使用它:

    final PipedWriter pipedWriter = new PipedWriter();
    PipedReader pipedReader = new PipedReader( pipedWriter, pipeBufferSize);
    final ErrorDelegatingReaderDecorator errorDelegatingReader = new ErrorDelegatingReaderDecorator( pipedReader );

    executorService.execute( new Runnable( ) {
        @Override
        public void run() {
            try 
            {
                //do something that writes into the writer and can throw an error
            } catch (Exception e) {
                errorDelegatingReader.setDelegatedThrowable(e);
                LOGGER.error( "Error while processing excel file.", e );
            }
            finally {
                try {
                    pipedWriter.close();
                } catch (IOException e) {
                    LOGGER.error( "Error while closing printwriter.", e );
                }
            }
        }
    });
    //Giving out the decorated reader to the reader thread.

权衡

由于我必须从装饰读取器的方法的finally部分抛出异常,所以我必须捕获Throwable,并且必须将其包装到IOException中。它有点难看,但它不太可能发生在装饰过的 PipedReader 上。

为什么它首先不起作用

同样有趣的是,我还讲述了我如何间歇性地返回 EOF 失败而不是抛出错误:我在编写器 block 中使用了 try-with-resources。结果是,我的编写器首先关闭,然后我在装饰器中设置了错误。如果在两者之间我有一个读取,那么它就变成了 EOF。所以我用普通的旧的finally block 替换了它,现在顺序可以了。

关于java - 将 PipedWriter+PipedReader 对的写入器线程的错误委托(delegate)给读取器线程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25033516/

相关文章:

java - Android EditText 验证

c - 在 C 中获取用户输入的最简单方法是什么?

c++ - 使用 ifstream 读取文件

io - 如果我使用 libaio + fsync() 会怎样?

java - 构造期间的线程安全

java - java中如何监控文本文件

java - 如何解决 Android 中严重的延迟问题

java - 如何排除 Fortify 中的警告?

java - 为什么下面的 java 代码没有产生错误? (访问修饰符)

java - 以有限的执行次数高效地线程安全地实现业务服务操作