9

我在阻塞上创建了一个ObjectInputSteamand并试图同时读取和写入。我的代码是这样的:ObjectOutputStreamSocketChannel

socketChannel = SocketChannel.open(destNode);
objectOutputStream = new ObjectOutputStream(Channels.newOutputStream(socketChannel));
objectInputStream = new ObjectInputStream(Channels.newInputStream(socketChannel));

Thread replyThread = new Thread("SendRunnable-ReplyThread") {
    @Override
    public void run() {
        try {
            byte reply = objectInputStream.readByte();//(A)
            //..process reply
        } catch (Throwable e) {
            logger.warn("Problem reading receive reply.", e);
        }
    }
};
replyThread.start();

objectOutputStream.writeObject(someObject);//(B)
//..more writing

问题是行 (B) 处的写入阻塞,直到行 (A) 处的读取完成(阻塞返回的对象SelectableChannel#blockingLock())。但是应用程序逻辑规定,在所有写入完成之前,读取不会完成,因此我们有一个有效的死锁。

SocketChanneljavadocs说支持并发读写。

当我尝试常规的 Socket 解决方案时,我没有遇到这样的问题:

Socket socket = new Socket();
socket.connect(destNode);
final OutputStream outputStream = socket.getOutputStream();
objectOutputStream = new ObjectOutputStream(outputStream);
objectInputStream = new ObjectInputStream(socket.getInputStream());

但是,我无法利用FileChannel#transferTo(...)

4

4 回答 4

5

This seems to be a bug in java.nio.channels.Channels (thanks to Tom Hawtin; post it as an answer next time). A good description and workaround are described here (actually a duplicate of the bug Tom listed):

I tested the workaround and it works.

于 2008-10-07T15:41:00.267 回答
4

错误报告中的解决方法对我有用。值得注意的是,只有一个输入或输出需要被包装以使解决方法起作用 - 因此,如果性能在一个方向上特别重要,那么您可以包装不太重要的一个,并确保另一个将获得所有可用的优化它。

public InputStream getInputStream() throws IOException {
    return Channels.newInputStream(new ReadableByteChannel() {
        public int read(ByteBuffer dst) throws IOException {
            return socketChannel.read(dst);
        }
        public void close() throws IOException {
            socketChannel.close();
        }
        public boolean isOpen() {
            return socketChannel.isOpen();
        }
    });
}

public OutputStream getOutputStream() throws IOException {
    return Channels.newOutputStream(socketChannel);
}
于 2009-02-13T15:45:30.897 回答
2

如果您想同时使用 InputStream 和 OutputStream 与 SocketChannel,从查看源代码来看,您似乎需要调用 SocketChannel.socket() 并使用行为略有不同的流。

于 2008-10-06T16:23:53.677 回答
0

有趣的错误!你说你不能使用 FileChannel#transferTo。在传递给 FileChannel#transferTo 之前,如何使用 Channesl#newChannel 将非 NIO 套接字的 I/O 流包装到通道中?

于 2008-10-07T18:43:11.070 回答