Java “为什么?”;管道;一个麻将?

Java “为什么?”;管道;一个麻将?,java,io,pipe,Java,Io,Pipe,为什么下面的方法挂起 public void pipe(Reader in, Writer out) { CharBuffer buf = CharBuffer.allocate(DEFAULT_BUFFER_SIZE); while( in.read(buf) >= 0 ) { out.append(buf.flip()); } } 公共空白管道(读卡器输入、写卡器输出){ CharBuffer buf=CharBuffer.allocate(默认缓冲区大小

为什么下面的方法挂起

public void pipe(Reader in, Writer out) { CharBuffer buf = CharBuffer.allocate(DEFAULT_BUFFER_SIZE); while( in.read(buf) >= 0 ) { out.append(buf.flip()); } } 公共空白管道(读卡器输入、写卡器输出){ CharBuffer buf=CharBuffer.allocate(默认缓冲区大小); while(in.read(buf)>=0){ out.append(buf.flip()); } }
回答我自己的问题:你必须在
read
s之间调用
buf.clear()。大概,
read
挂起是因为缓冲区已满。正确的代码是

public void pipe(Reader in, Writer out) { CharBuffer buf = CharBuffer.allocate(DEFAULT_BUFFER_SIZE); while( in.read(buf) >= 0 ) { out.append(buf.flip()); buf.clear(); } } 公共空白管道(读卡器输入、写卡器输出){ CharBuffer buf=CharBuffer.allocate(默认缓冲区大小); while(in.read(buf)>=0){ out.append(buf.flip()); buf.clear(); } }
我认为这是一个僵局。in.read(buf)锁定CharBuffer并阻止out.append(buf)调用

这是假设CharBuffer在实现中使用锁(某种锁)。API如何描述类CharBuffer


编辑:对不起,我脑子里有点短路。。。我把它和其他东西搞混了。

CharBuffers与读者和作者的关系不像你想象的那样干净。特别是,没有
Writer.append(charbufferbuf)
方法。问题片段调用的方法是
Writer.append(CharSequence seq)
,它只调用
seq.toString()
CharBuffer.toString()
方法确实返回缓冲区的字符串值,但不会耗尽缓冲区。对
Reader.read(CharBuffer buf)
的后续调用获取一个已满的缓冲区,因此返回0,迫使循环无限期地继续

虽然这感觉像是挂起,但实际上每次通过循环时都会将第一次读取的缓冲区内容附加到写入程序。因此,您要么开始在目标中看到大量输出,要么编写器的内部缓冲区将增长,这取决于编写器的实现方式

尽管这很烦人,但我还是建议使用char[]实现,因为CharBuffer解决方案每次通过循环都会生成至少两个新的char[]

public void pipe(Reader in, Writer out) throws IOException {
    char[] buf = new char[DEFAULT_BUFFER_SIZE];
    int count = in.read(buf);
    while( count >= 0 ) {
        out.write(buf, 0, count);
        count = in.read(buf);
    }
}

如果您需要支持两个字符编码之间的转换,我建议只使用此选项,否则,即使您是管道字符,也最好使用ByteBuffer/Channel或byte[]/IOStream实现。

挂起?看看可读API,如果缓冲区已满,我希望它在每次读取时都忙于循环返回0,但这只是猜测,因为它没有明确说明“尝试读取”的含义。挂起可能意味着,因为您正在成倍地写入输出,所以您阻止了输出。我没有检查循环的详细行为。读取块或重复返回0。净效果:循环永远不会终止。我想,要发生阻塞,输出流必须具有有限的容量,并且不会被耗尽,比如循环缓冲区——这种情况非常罕见。也许我很特别,我通常用“挂起”来表示死锁,而不是活锁。