Newsletter sign-up
View all newsletters

Enterprise Java Newsletter
Stay up to date on the latest tutorials and Java community news posted on JavaWorld

Sponsored Links

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

Five ways to maximize Java NIO and NIO.2

Build more responsive Java applications with the New Input/Output APIs

  • Print
  • Feedback

Page 4 of 5

More NIO on JavaWorld

See the following JavaWorld articles for more background on the java.nio package APIs.

3. Channels: Promise and reality

In NIO, a channel can be any object that reads or writes. Its job is to abstract files and sockets. NIO channels support a consistent collection of methods, so it's possible to program without having special cases depending on whether stdout, a network connection, or some other channel is actually in use. Channels share this characteristic of the streams of Java's basic I/O. Streams provide blocking I/O; channels support asynchronous I/O.

While NIO is often promoted for its performance advantages, it's more precise to say it is highly responsive. In some cases NIO actually performs worse than basic Java I/O. For simple sequential reads and writes of small files, for instance, a straightforward streams implementation might be two or three times faster than the corresponding event-oriented channel-based coding. Also, non-multiplexed channels -- that is, channels in separate threads -- can be much slower than channels that register their selectors in a single thread.

The next time you need to define a programming problem in terms of dimensions pertinent to streams or channels, try asking the following questions:

  • How many I/O objects must you read and write?
  • Is there a natural sequence between different I/O objects or might they all need to happen simultaneously?
  • Do your I/O objects only last for a short interval or are they likely to persist during the lifetime of your process?
  • Is it more natural to do your I/O in a single thread or several distinct ones?
  • Is network traffic likely to look the same as local I/O or do the two have different patterns?

This sort of analysis is good practice for deciding when to use streams or channels. Remember: NIO and NIO.2 don't replace basic I/O; they just supplement it.

4. Memory mapping -- where it counts

The most consistently dramatic performance improvement in the use of NIO involves memory mapping. Memory mapping is an OS-level service that makes segments of a file appear for programming purposes like areas of memory.

Memory mapping has a number of consequences and implications, more than I'll get into here. At a high level, it helps make I/O happen at the speed of memory access, rather than file access. The former is often two orders of magnitude faster than the latter. Listing 3 is a minimal demonstration of NIO's memory-mapping facility.

Listing 3. Memory mapping in NIO

  import java.io.RandomAccessFile;
  import java.nio.MappedByteBuffer;
  import java.nio.channels.FileChannel;
  
    public class mem_map_example {
      private static int mem_map_size = 20 * 1024 * 1024;
      private static String fn = "example_memory_mapped_file.txt";
  
      public static void main(String[] args) throws Exception {
          RandomAccessFile memoryMappedFile = new RandomAccessFile(fn, "rw");
         
          //Mapping a file into memory
          MappedByteBuffer out = memoryMappedFile.getChannel().map(FileChannel.MapMode.READ_WRITE, 0, mem_map_size);
        
          //Writing into Memory Mapped File
          for (int i = 0; i < mem_map_size; i++) {
              out.put((byte) 'A');
          }
          System.out.println("File '" + fn + "' is now " + Integer.toString(mem_map_size) + " bytes full.");
        
          // Read from memory-mapped file.
          for (int i = 0; i < 30 ; i++) {
              System.out.print((char) out.get(i));
          }
          System.out.println("\nReading from memory-mapped file '" + fn + "' is complete.");
      }
  }

The small model in Listing 3 quickly creates a 20-megabyte file, example_memory_mapped_file.txt, fills the file with the character A, then reads the first 30 bytes of the file. In practical cases, memory mapping is interesting not only for the raw speed of I/O, but also because several different readers and writers can attach simultaneously to the same file image. This technique is powerful enough to be dangerous, but in the right hands it makes for exceedingly fast implementations. Wall Street trading operations notoriously leverage memory mapping in order to gain seconds, or even milliseconds, on competitors.

  • Print
  • Feedback

Resources