|
|
Optimize with a SATA RAID Storage Solution
Range of capacities as low as $1250 per TB. Ideal if you currently rely on servers/disks/JBODs
Java uses an extremely elegant input/output (I/O) model, based on the idea of a stream. A stream is an object that produces or consumes a string of bytes. Streams can be chained together in conjunction with filtering routines and extended to handle other kinds of data. The stream model is very flexible, but not too fast. It's fine for many applications, but some systems require just about as much speed as the hardware can handle. Sometimes the stream model won't cut it.
The New Input/Output (NIO) libraries introduced in Java 2 Platform, Standard Edition (J2SE) 1.4 address this problem. NIO uses a buffer-oriented model. That is, NIO deals with data primarily in large blocks. This eliminates the overhead caused by the stream model and even makes use of OS-level facilities, where possible, to maximize throughput.
First I look at how NIO works, and then I put it to use in a high-speed server application.
Note: You can download this article's source code from Resources.
NIO is based on two concepts, channels and buffers. Channels are roughly analogous to streams used in the stream model. Buffers do not have a precise analog in the stream model.
The basic streams, InputStream and OutputStream, can read and write bytes; subclasses of these stream classes can read and write other kinds of data. In NIO, all data is
read and written via buffers. See Figure 1 for a comparison of the two models.

Figure 1. The stream model uses streams and bytes; the NIO model uses channels and buffers
Also notice that while the stream model distinguishes between InputStreams and OutputStreams, NIO uses one kind of object—a Channel—for both.
The main advantage of buffers is that they deal with data in bulk. You can read and write large blocks of data, and the size of the buffers you use is only limited by the amount of memory you are willing to allocate to them.
Another more subtle advantage of buffers is that they can represent system-level buffers. Some operating systems use a unified
memory scheme that allows I/O without copying data from operating system memory into application memory. Some implementations
provide Buffer objects that represent these system-level buffers directly, which means you can read and write data with minimal data copying
(see Figure 2).

Figure 2. System buffers allow you to use system-level buffers directly, avoiding extraneous data copying
The select facility provides an excellent way to deal with a large number of data sources simultaneously. It takes its name from a Unix
system call—select()—that provides the same kind of facility to a C program running on a Unix system.
Normally, I/O is done via blocking system calls. When you call a read() method on an input stream, the method blocks until some data is available. If you're reading from a local file, you don't
have to wait long for the data to show up. On the other hand, if you are reading from a network file server or a network socket
connection, you might wait longer. While you're waiting, your reading thread can't do anything else.