Vous êtes sur la page 1sur 4

Discover the benefits of java.

nio's new
features
by Peter V. Mikhalenko | Jul 19, 2006 7:00:00 AM

Tags: benefit, Peter V. Mikhalenko, Regular I/O, NIO API, I/O..., Java Tips Newsletter

0 comment(s)

• Email
• Share
o Digg
o Yahoo! Buzz
o Twitter
o Facebook
o Google
o del.icio.us
o StumbleUpon
o Reddit
o Newsvine
o Technorati
o LinkedIn
• Save
• Print
• Recommend
• 3

Takeaway: The java.nio package, which was introduced in Java 1.4, allows developers to
achieve greater performance in data processing and offers better scalability. Peter V.
Mikhalenko explains how to use many of the NIO API's new features.

The java.nio (new input/output) package, which was introduced in Java 1.4, allows for I/O
more like what is available in other lower-level languages like C. Many developers think the
new capabilities offer just non-blocking I/O operations; however, the new features offer
many other new and interesting features, which include:

• You can memory map files.


• You can read and write blocks of data direct from disk, rather than byte by byte. (It
deals with the endian problem when you fish the data out of the buffer not during the
read.)
• You can do non-blocking asynchronous I/O.
• You can lock files or parts of files.

Regular I/O is based on stacking the methods you need in a rather verbose and highly
asymmetric way in InputStream, Reader, and BufferedReader. The NIO design is cleaner,
simpler, and more efficient; you could even do all of your I/O with NIO if you choose. In this
article, I'll explore most of these features and discuss how they to use them.
Communication channels
The NIO API introduces a new primitive I/O abstraction called channel. A channel represents
an open connection to an entity such as a hardware device, a file, a network socket, or a
program component that is capable of performing one or more distinct I/O operations, for
example reading or writing. As specified in the java.nio.channels.Channel interface, channels
are either open or closed, and they are both asynchronously closeable and interruptible.

Get Java tips in your inbox


Delivered each Thursday, our free Java newsletter provides insight and hands-on tips you need to unlock the full
potential of this programming language.
Automatically sign up today!

A nice feature of a channel is that one thread can be blocked on an operation, and another
thread can close the channel. When the channel closes, the blocked thread awakens with an
exception indicating that the channel is closed.

There are several interfaces that extend the channel interface, each of which specifies a new
I/O operation. Here's information about these interfaces:

• The ReadableByteChannel interface specifies a read() method that reads bytes from
the channel into a buffer.
• The WritableByteChannel interface specifies a write() method that writes bytes from a
buffer to the channel.
• The ScatteringByteChannel and GatheringByteChannel interfaces extend the
ReadableByteChannel and WritableByteChannel interfaces, respectively, adding
read() and write() methods that take a sequence of buffers rather than a single buffer.

The FileChannel class supports the usual operations of reading bytes from and writing bytes
to a channel connected to a file, as well as those of querying and modifying the current file
position and truncating the file to a specific size. It defines methods for acquiring locks on the
whole file or on a specific region of a file; these methods return instances of the FileLock
class. Finally, it defines methods for forcing updates to the file to be written to the storage
device that contains it for efficiently transferring bytes between the file and other channels,
and mapping a region of the file directly into memory.

Configuring channels

You can configure channels for blocking or non-blocking operations. When blocking calls to
read, write, or other operations, do not return until the operation completes. Large writes over
a slow socket, for example, can take a long time. In non-blocking mode, a call to write a large
buffer over a slow socket would just queue up the data (probably in an operating system
buffer, though it could even queue it up in a buffer on the network card) and return
immediately. The thread can move on to other tasks, while the operating system's I/O
manager finishes the job.
Moving on from file channels takes us to channels for reading from and writing to socket
connections. You can also use these channels in a blocking or non-blocking fashion. In the
blocking fashion, they just replace the call to connect or accept, depending on whether you
are a client or a server. In the non-blocking fashion, there is no equivalent. Listing A is an
example of how you can send the string "Hello there!" to 1234 port and get a response.

Buffers in NIO
Buffer classes provide a mechanism to store a set of primitive data elements in an in-memory
container. In addition to its content, a buffer has a position, which is the index of the next
element to be read or written, and a limit, which is the index of the first element that should
not be read or written. The base Buffer class defines these properties, as well as methods for
clearing, flipping, and rewinding; for marking the current position; and for resetting the
position to the previous mark. There is a buffer class for each non-Boolean primitive type:
ByteBuffer, CharBuffer, DoubleBuffer, LongBuffer, etc.

Each of these buffer classes support a set of get- and put- methods for reading and writing
data, and there are a couple of get- and put- methods for each primitive type that can
potentially be read or written from/to the corresponding buffer type. For ByteBuffer, for
example, there are methods getChar(), putChar(), getByte(), putByte(), getShort(), putShort(),
and some others.

There is one specialized form of direct ByteBuffer known as a MappedByteBuffer. This class
represents a buffer of bytes mapped to a file. To map a file to a MappedByteBuffer, you first
must get the channel for a file. Once the MappedByteBuffer has been created, you can access
it like any other ByteBuffer. In this particular case though, it is read-only, so any attempt to
put something with the putXxxx()method will throw a NonWritableChannelException
exception.

The java.nio.charset package contains charsets, decoders, and encoders for translating
between bytes and Unicode characters. A decoder is an engine that transforms bytes in a
specific charset into characters; an encoder is an engine that transforms characters into bytes.
In Listing A, the decoder and encoder are used for recoding requests and responses on the fly.

Non-blocking operations
Non-blocking operations are the most popular and widely used feature of the new I/O API. In
order to configure the channel to be non-blocking, you should call the configureBlocking()
method. For SocketChannel, this is how you do that:

String host = ...;

InetSocketAddress socketAddress =
new InetSocketAddress(host, 1234);

channel = SocketChannel.open();

channel.configureBlocking(false);

channel.connect(socketAddress);
After calling the connect() method, it will return the execution immediately. Then, you have
to point out how to handle such channel connections. If a channel is selectable (i.e., it can be
multiplexed via the Selector class and extends the SelectableChannel class), you can register
your channel with Selector (via the register() method), and then subscribe to specific events;
it will notify you when something specified will happen. The events are specified by fields of
the SelectionKey class. Here is how you do this:

Selector selector = Selector.open();


channel.register(selector,
SelectionKey.OP_CONNECT | SelectionKey.OP_READ);

To find out if something interesting has happened, you can put a while loop in its own thread.

When you receive a notification, it can be about any of the selected events you were
interested in; you will get the Set of ready objects through the selectedKeys method and
iterate. The element in the Set is a SelectionKey instance. As long as you have subscribed to
the OP_CONNECT and OP_READ events of a ChannelSocket, you have to check
isConnectable() and isReadable() properties (see Listing B.) We are removing the currently
processed entry with the remove() method because the set of channels can change while you
are processing them.

Conclusion
Although many developers think the new I/O capabilities just offer non-blocking I/O
operations, this is not completely accurate. The new I/O offers several new concepts (such as
channels) and new ways of working with I/O operations through buffers, charsets, and file
mapping. The java.nio package allows developers to achieve greater performance in data
processing, as well as better scalability.

For more in-depth details about NIO features, take a look at Sun's JSR 51 and the quick Sun
NIO guide.

Peter V. Mikhalenko is a Sun certified professional who works for Deutsche Bank as business
consultant.

Vous aimerez peut-être aussi