Summary
Improve the performance and reliability of the java.nio.channel.SelectableChannel implementations by separating the blocking and non-blocking code paths.
Problem
SocketChannel, ServerSocketChannel, DatagramChannel, Pipe.SourceChannel and Pipe.SinkChannel implement InterruptibleChannel so that blocking I/O operations can be interrupted (and the channel closed) by Thread.interrupt. This behavior is problematic for high-performance libraries that use non-blocking I/O. Interrupting a thread has the potential to close a random channel that the thread happens to perform an I/O operation on. In addition, the implementation of async close and interrupt has been highly problematic with reliability issues and complex synchronization adding significant overhead to performance critical code paths.
Usability, reliability, and performance can been improved significantly by limiting interruption to channels that are configured blocking. However, re-implementing this complex area results in a few behavior changes:
Invoking configureBlocking(true) on a selectable channel will now block until outstanding I/O operations have completed. The specification allows this but the implementation in the JDK didn't historically synchronize and so didn't block. While unlikely, this may be observable by code outside of the JDK that has assumed it can change a selectable channel to non-blocking whilst a thread is blocked in an I/O operation.
Invoking an I/O operation on a channel configured non-blocking and with the interrupt status set no longer closes the channel. This will be welcomed by many but it's possible (although unlikely) that something depends on long standing and unspecified behavior.
Closing a connected SocketChannel that is registered with a
Selector
will delay closing the connection until the closed channel is flushed from all Selectors that it is registered with. The long standing behavior has been to close the connection (at least on Linux and macOS, not Windows) and to delay closing the file descriptor until the closed channel is flushed from all Selectors. The change is necessary for reliability reasons but it may be observed in environments that do not perform any selection operations to flush closed channels. To mitigate this behavior change, the implementation will shutdown the connection for writing so that at least the peer will read EOF. However the new behavior may initially puzzle developers that usenetstat
and other networking tools to get information about network connections.
Solution
Re-implement the I/O operations (read, write, accept, connect, finishConnect) defined by SocketChannel, ServerSocketChannel, DatagramChannel, Pipe.SourceChannel and Pipe.SinkChannel. When configured blocking, any thread that potentially blocks on an I/O operation can be interrupted so that the I/O operation is aborted and the channel closed as per the InterruptibleChannel specification. When configured non-blocking threads doing non-blocking I/O operations can be interrupted (meaning their interrupt status is set) but the channel is not closed.
Specification
There are no specification changes as InterruptibleChannel does not specify the behavior for non-blocking I/O operations.
- csr of
-
JDK-8198562 (ch) Separate blocking and non-blocking code paths (part 1)
-
- Resolved
-