An Introduction to Java NIO and NIO.2
Non-Blocking I/O
Prior to JDK1.4, threads engaged in network I/O exhibited the following characteristics:
- multiple threads for polling devices for readiness
- required dedicating a thread to each socket connection
- blocking until data is available
class Server implements Runnable { public void run() { try { ServerSocket ss = new ServerSocket(PORT); while (!Thread.interrupted()) new Thread(new Handler(ss.accept())).start(); // one thread per socket connection // every thread created this way will essentially block for I/O } catch (IOException ex) { /* ... */ } }
With functionality introduced in JSR-51, it is possible to set Channels in a non-blocking mode, under the watch of a Selector that has the ability to recognize/sense when one or more channels become available for data transfer. This frees the application from having to dedicate threads for blocking on devices awaiting data or implementing expensive polling processes. The following UML diagram shows the significant methods of Selector, SelectableChannel and SelectionKey.
Figure 3. Selector Topology
Some notes about non-blocking I/O:
- In non-blocking mode, an I/O operation never blocks (methods return immediately),
- In non -blocking mode, an I/O operation may transfer fewer bytes than were requested (partial read or write) or possibly no bytes at all.
- FileChannel does not support non-blocking file operations.
- Non-Blocking API is not the same as asynchronous API (JSR-203 - part of JDK 1.7).
Channels that support Network I/O
A socket is conceptually an endpoint for communication between two machines. Below is a UML of the java.nio classes showing significant methods that support network I/O (excluding scattering reads and gathering writes).
Figure 4. Network Channels
SelectableChannel
A channel that can be asynchronously closed and interrupted. Only SelectableChannels can be multiplexed /managed with Selectors.
The following methods provide for the configuration and management of SelectableChannels:
register()
creates a SelectionKey as a final product of performing the registration with a given Selector. It takes a Selector Object, interest set for Selector to monitor and an optional attachment as parameters.configureBlocking()
Sets the blocking mode on/off. Choose this method carefully--for all practical purposes, you only call this method once to initiate the non-blocking behavior.validOps()
An integer containing the operation set bitmap.keyFor(Selector)
Retrieves the SelectionKey representing the channel's registration with the given selector.
SocketChannel
- A partial abstraction of TCP sockets
- Contains an associated java.net.Socket used for binding and shutdown operations.
- Capable of connecting (using its associated java.net.Socket), reading and writing (using ByteBuffer).
- Extends SelectableChannel (discussed below) to support non-blocking connections so that it could be multiplexed via a Selector (discussed below).
- Is a Select-able channel for stream-oriented connecting sockets
Creating a SocketChannel
//open the channel to create it SocketChannel socketChannel = SocketChannel.open(); //create and prepare a buffer for data-transfer (read and ByteBuffer buffer = ByteBuffer.allocate(1000); //try connecting to the server socketChannel.connect(new InetSocketAddress(host, port)); //read the response - prepare to deal with partial reads buffer.clear(); for (;;) { if (in.read(buffer) < 0 && !buffer.hasRemaining()) break; // No more bytes to transfer buffer.flip(); //process the request out.write(buffer) buffer.compact(); // In case of partial write }
DatagramChannel
- A partial abstraction of network UDP (datagram).
- Capable of connecting (using its associated java.net.DatagramSocket), reading and writing (using ByteBuffer).
- Is a Select-able channel for datagram-oriented Sockets.
Creating a DatagramChannel
//open the channel to create it DatagramChannel datagramChannel = DatagramChannel.open(); //set the non-blocking mode on datagramChannel.configureBlocking(false); //try connecting to the socket datagramChannel.connect(new InetSocketAddress(host, port))
ServerSocketChannel
- A partial abstraction of stream-oriented Sockets.
- Contains an associated java.net.ServerSocket that could be used for binding operations.
- " Is a Select-able channel for stream-oriented Sockets with support for non-blocking connections so that it could be multiplexed via a Selector
Creating a non-blocking ServerSocketChannel
//open the channel first before accepting the connections ServerSocketChannel serSocketChannel = ServerSocketChannel.open(); //you could bind using the associated ServerSocket serSocketChanne1.socket().bind(new InetSocketAddress(port)); //set the non-blocking mode on serSocketChannel.configureBlocking(false);
Thanks for reading and stop in next week where we'll dig deep into the new java.nio (New I/O) package.
References
Monitoring Direct BuffersNIO Java Specification
Article on Concurrent processing
Page 3 of 3
This article was originally published on September 9, 2009