Java';s ReadableByTechannel不一致行为
当我使用Channels.newChannel(is)java标准库从InputStream创建一个通道时,返回一个ReadableByteChannelImpl,即:Java';s ReadableByTechannel不一致行为,java,nio,Java,Nio,当我使用Channels.newChannel(is)java标准库从InputStream创建一个通道时,返回一个ReadableByteChannelImpl,即: private static class ReadableByteChannelImpl extends AbstractInterruptibleChannel // Not really interruptible implements ReadableByteChannel {
private static class ReadableByteChannelImpl
extends AbstractInterruptibleChannel // Not really interruptible
implements ReadableByteChannel
{
InputStream in;
private static final int TRANSFER_SIZE = 8192;
private byte buf[] = new byte[0];
private boolean open = true;
private Object readLock = new Object();
ReadableByteChannelImpl(InputStream in) {
this.in = in;
}
public int read(ByteBuffer dst) throws IOException {
int len = dst.remaining();
int totalRead = 0;
int bytesRead = 0;
synchronized (readLock) {
while (totalRead < len) {
int bytesToRead = Math.min((len - totalRead),
TRANSFER_SIZE);
if (buf.length < bytesToRead)
buf = new byte[bytesToRead];
if ((totalRead > 0) && !(in.available() > 0))
break; // block at most once
try {
begin();
bytesRead = in.read(buf, 0, bytesToRead);
} finally {
end(bytesRead > 0);
}
if (bytesRead < 0)
break;
else
totalRead += bytesRead;
dst.put(buf, 0, bytesRead);
}
if ((bytesRead < 0) && (totalRead == 0))
return -1;
return totalRead;
}
}
protected void implCloseChannel() throws IOException {
in.close();
open = false;
}
}
这种奇怪行为背后的原因是什么
另外,扩展AbstractInterruptibleChannel而不使该通道真正可中断的动机是什么?如果它已经读取了至少一个字节,并且底层流宣布没有字节,它将不会阻塞。请注意,
InputStream#available()
即使在某些字节可用的情况下也可以返回零,但它不应保证在无阻塞的情况下读取的字节数超过可读取的字节数。因此,这个ReadableByteChannel
努力读取至少一个字节——假设提供的ByteBuffer
至少有一个字节的空间——并且,在这样做之后,将不会再次尝试读取底层流,除非流承诺在不阻塞的情况下有更多字节可用
至于为什么techannelimpl扩展了ReadableByteChannelImpl
,我怀疑这是为了确保包装好的InputStream
在调用时能够正确关闭,而它的契约会被进一步细化。扩展AbstractInterruptableChannel
允许ReadableByteChannelImpl
借用其线程安全的打开关闭状态保护
正如您所说,这是一种虚假的广告,不具有真正的可中断性,但它可以容忍从单独的线程关闭,并使这样做具有幂等性。如果它已经读取了至少一个字节,并且底层流宣布没有字节是可中断的,它将不会阻塞。请注意,
InputStream#available()
即使在某些字节可用的情况下也可以返回零,但它不应保证在无阻塞的情况下读取的字节数超过可读取的字节数。因此,这个ReadableByteChannel
努力读取至少一个字节——假设提供的ByteBuffer
至少有一个字节的空间——并且,在这样做之后,将不会再次尝试读取底层流,除非流承诺在不阻塞的情况下有更多字节可用
至于为什么techannelimpl扩展了ReadableByteChannelImpl
,我怀疑这是为了确保包装好的InputStream
在调用时能够正确关闭,而它的契约会被进一步细化。扩展AbstractInterruptableChannel
允许ReadableByteChannelImpl
借用其线程安全的打开关闭状态保护
正如你所说,这是一个虚假的广告,不是真正的可中断的,但它容忍从一个单独的线程关闭,并使这样做是幂等的。是的,我自己已经得到了。在第一次read()调用期间阻塞的主要原因是没有任何可靠的方法来检查底层流是否为空,而不实际读取它。在第一次read()调用期间阻塞的主要原因是没有任何可靠的方法来检查底层流是否为空,而不实际读取它。
if ((totalRead > 0) && !(in.available() > 0))
break; // block at most once