当使用空缓冲区调用read()时,PipedInputStream总是会阻塞。有没有办法阻止这个?

时间:2012-04-30 12:45:34

标签: java inputstream blocking

我搜索了我能找到的与PipedInputStreams和PipedOutputStreams有关的所有问题,但没有找到任何可以帮助我的东西。希望这里有人会遇到类似的东西。

背景

我有一个类从任何java.io.InputStream读取数据。该类有一个名为 hasNext()的方法,它检查给定的InputStream是否有数据,如果找到数据则返回true,否则返回false。这个hasNext()方法与其他InputStream完美配合,但是当我尝试使用PipedInputStream(从另一个Thread中的PipedOutputStream提供,封装在下面的inputSupplier变量中)时,它会挂起。在查看hasNext()方法如何工作之后,我使用以下代码重新创建了该问题:

public static void main(String [] args){
    PipedInputStream inputSourceStream = new PipedInputStream(inputSupplier.getOutputStream());
    byte[] input = new byte[4096];
    int bytes_read = inputSourceStream.read(input, 0, 4096);
}

inputSupplier只是我编写的一个小类的实例,它在自己的线程中使用本地PipedOutputStream运行,以避免死锁。

问题 所以,我的问题是hasNext()方法调用流上的PipedInputStream.read()方法,以确定是否有任何数据要读取。这会导致阻塞读取操作永不退出,直到某些数据到达才能读取。这意味着如果流为空,我的hasNext()函数将永远不会返回false(或者根本不会)。

免责声明:我知道available()方法,但所有这些都告诉我,没有可用的字节,而不是我们在流的末尾(可能是Stream的任何实现),所以阅读()需要检查这个。

[编辑] 我最初使用PipedInputStream的目的是模拟“突发”数据源。也就是说,我需要有一个我可以偶尔编写的Stream,看看我的hasNext()方法是否会在读取时检测到Stream上有新数据。如果有更好的方法,那么我会很高兴听到它!

2 个答案:

答案 0 :(得分:0)

Java SE 6及更高版本(如果我错了,请纠正我)附带java.nio软件包,该软件包专为异步I / O而设计,听起来就像您所描述的那样

答案 1 :(得分:0)

我讨厌这个旧问题,但这接近谷歌的结果,我刚刚为自己找到了一个解决方案:这个循环字节缓冲区公开了输入和输出流,并且read方法返回当没有数据时立即-1。一点点线程,您的测试类可以按照您想要的方式提供数据。

http://ostermiller.org/utils/src/CircularByteBuffer.java.html

修改

原来我误解了上面这个类的文档,当调用read()的线程被中断时它只返回-1。我快速修改了read方法,它给了我想要的东西(原始代码注释掉了,唯一的新代码是用else代替else if

@Override public int read(byte[] cbuf, int off, int len) throws IOException {
        //while (true){
            synchronized (CircularByteBuffer.this){
                if (inputStreamClosed) throw new IOException("InputStream has been closed; cannot read from a closed InputStream.");
                int available = CircularByteBuffer.this.available();
                if (available > 0){
                    int length = Math.min(len, available);
                    int firstLen = Math.min(length, buffer.length - readPosition);
                    int secondLen = length - firstLen;
                    System.arraycopy(buffer, readPosition, cbuf, off, firstLen);
                    if (secondLen > 0){
                        System.arraycopy(buffer, 0, cbuf, off+firstLen,  secondLen);
                        readPosition = secondLen;
                    } else {
                        readPosition += length;
                    }
                    if (readPosition == buffer.length) {
                        readPosition = 0;
                    }
                    ensureMark();
                    return length;
                //} else if (outputStreamClosed){
                } else {  // << new line of code
                    return -1;
                }
            }
            //try {
            //    Thread.sleep(100);
            //} catch(Exception x){
            //    throw new IOException("Blocking read operation interrupted.");
            //}
        //}
    }

```