Java I/O and NIO.2
---Five ways to maximize Java NIO and NIO.2
---Build more responsive Java applications with the New Input/Output APIs

Java NIO -- the New Input/Output API package-- was introduced with J2SE 1.4 in 2002. Java NIO's purpose was to improve the programming of I/O-intensive chores on the Java platform. A decade later, many Java programmers still don't know how to make the best use of NIO, and even fewer are aware that Java SE 7 introduced More New Input/Output APIs (NIO.2). In this tutorial you'll find five easy examples that demonstrate the advantages of the NIO and NIO.2 packages in common Java programming scenarios. The primary contribution of NIO and NIO.2 to the Java platform is to improve performance in one of the core areas of Java application development: input/output processing. Neither package is particularly easy to work with, nor are the New Input/Output APIs required for every Java I/O scenario. Used correctly, though, Java NIO and NIO.2 can slash the time required for some common I/O operations. That's the superpower of NIO and NIO.2, and this article presents five relatively simple ways to leverage it:

Change notifiers (because everybody needs a listener)
    Selectors help multiplex
    Channels -- promise and reality
    Memory mapping -- where it counts
    Character encoding and searching

The NIO context
How is it that a 10-year-old enhancement is still the New Input/Output package for Java? The reason is that for many working Java programmers the basic Java I/O operations are more than adequate. Most Java developers don't have to learn NIO for our daily work. Moreover, NIO isn't just a performance package. Instead, it's a heterogeneous collection of facilities related to Java I/O. NIO boosts Java application performance by getting "closer to the metal" of a Java program, meaning that the NIO and NIO.2 APIs expose lower-level-system operating-system (OS) entry points. The tradeoff of NIO is that it simultaneously gives us greater control over I/O and demands that we exercise more care than we would with basic I/O programming. Another aspect of NIO is its attention to application expressivity, which we'll play with in some of the exercises that follow.  For many developers the first encounter with NIO might happen during maintenance work: an application has correct functionality but is slow to respond, so someone suggests using NIO to accelerate it. NIO shines when it's used to boost processing performance, but its results will be closely tied to the underlying platform. (Note that NIO is platform dependent.) If you're using NIO for the first time, it will pay you to measure carefully. You might discover that NIO's ability to accelerate application performance depends not only on the OS, but on the specific JVM, host virtualization context, mass storage characteristics, and even data. Measurement can be tricky to generalize, however. Keep this in mind particularly if a mobile deployment is among your targets.And now, without further ado, let's explore five important facilities of NIO and NIO.2.

1. Change notifiers (because everybody needs a listener)
Java application performance is the common draw for developers interested in NIO or NIO.2. In my experience, however, NIO.2's file change notifier is the most compelling (if under-sung) feature of the New Input/Output APIs.
Many enterprise-class applications need to take a specific action when:

A file is uploaded into an FTP folder
    A configuration definition is changed
    A draft document is updated
    Another file-system event occurs

These are all examples of change notification or change response. In early versions of Java (and other languages), polling was typically the best way to detect change events. Polling is a particular kind of endless loop: check the file-system or other object, compare it to its last-known state, and, if there's no change, check back again after a brief interval, such as a hundred milliseconds or ten seconds. Continue the loop indefinitely. NIO.2 gives us a better way to express change detection. Listing 1 is a simple example.
Listing 1. Change notification in NIO.2

import java.nio.file.attribute.*;
  import java.io.*;
  import java.util.*;
  import java.nio.file.Path;
  import java.nio.file.Paths;
  import java.nio.file.StandardWatchEventKinds;
  import java.nio.file.WatchEvent;
  import java.nio.file.WatchKey;
  import java.nio.file.WatchService;
  import java.util.List;
  
  public class Watcher {
      public static void main(String[] args) {
          Path this_dir = Paths.get(".");    
          System.out.println("Now watching the current directory ...");  
   
          try {
              WatchService watcher = this_dir.getFileSystem().newWatchService();
              this_dir.register(watcher, StandardWatchEventKinds.ENTRY_CREATE);
   
              WatchKey watckKey = watcher.take();
   
              List<WatchEvent< &64;>> events = watckKey.pollEvents();
              for (WatchEvent event : events) {
                  System.out.println("Someone just created the file '" + event.context().toString() + "'.");
  
             }
   
         } catch (Exception e) {
             System.out.println("Error: " + e.toString());
         }
      }
  }

Compile this source, then launch the command-line executable. In the same directory, create a new file; you might, for example, touch example1, or even copy Watcher.class example1. You should see the following change notification message:
Someone just create the file 'example1'. This simple example illustrates how to begin accessing NIO's language facilities in Java. It also introduces NIO.2's Watcher class, which is considerably more straightforward and easy-to-use for change notification than the traditional I/O solution based on polling. NIO's notifiers are so much easier to use than the polling loops of old that it's tempting to neglect requirements analysis. But you should think through these semantics the first time you use a listener. Knowing when a file modification ends is more useful than knowing when it begins, for instance. That kind of analysis takes some care, especially in a common case like the FTP drop folder. NIO is a powerful package with some subtle "gotcha's"; it can punish a casual visitor.

2. Selectors and asynchronous I/O: Selectors help multiplex
Newcomers to NIO sometimes associate it with "non-blocking input/output." NIO is more than non-blocking I/O but the error makes sense: basic I/O in Java is blocking -- meaning that it waits until it can complete an operation -- whereas non-blocking, or asynchronous, I/O is one of the most-used NIO facilities. NIO's non-blocking I/O is event-based, as demonstrated by the file-system listener in Listing 1. This means that a selector (or callback or listener) is defined for an I/O channel, then processing continues. When an event occurs on the selector -- when a line of input arrives, for instance -- the selector "wakes up" and executes. All of this is achieved within a single thread, which is a significant contrast to typical Java I/O. Listing 2 demonstrates the use of NIO selectors in a multi-port networking echo-er, a program slightly modified from one created by Greg Travis in 2003 (see Resources). Unix and Unix-like operating systems have long had efficient implementations of selectors, so this sort of networking program is a model of good performance for a Java-coded networking program.
Listing 2. NIO selectors

import java.io.*;
  import java.net.*;
  import java.nio.*;
  import java.nio.channels.*;
  import java.util.*;
  
  public class MultiPortEcho
  {
    private int ports[];
    private ByteBuffer echoBuffer = ByteBuffer.allocate( 1024 );
  
    public MultiPortEcho( int ports[] ) throws IOException {
      this.ports = ports;
  
      configure_selector();
    }
  
    private void configure_selector() throws IOException {
      // Create a new selector
      Selector selector = Selector.open();
  
      // Open a listener on each port, and register each one
      // with the selector
      for (int i=0; i<ports.length; ++i) {
        ServerSocketChannel ssc = ServerSocketChannel.open();
        ssc.configureBlocking(false);
        ServerSocket ss = ssc.socket();
        InetSocketAddress address = new InetSocketAddress(ports[i]);
        ss.bind(address);
  
        SelectionKey key = ssc.register(selector, SelectionKey.OP_ACCEPT);
  
        System.out.println("Going to listen on " + ports[i]);
      }
  
      while (true) {
        int num = selector.select();
  
        Set selectedKeys = selector.selectedKeys();
        Iterator it = selectedKeys.iterator();
  
        while (it.hasNext()) {
          SelectionKey key = (SelectionKey) it.next();
  
          if ((key.readyOps() & SelectionKey.OP_ACCEPT)
            == SelectionKey.OP_ACCEPT) {
            // Accept the new connection
            ServerSocketChannel ssc = (ServerSocketChannel)key.channel();
            SocketChannel sc = ssc.accept();
            sc.configureBlocking(false);
  
            // Add the new connection to the selector
            SelectionKey newKey = sc.register(selector, SelectionKey.OP_READ);
            it.remove();
  
            System.out.println( "Got connection from "+sc );
          } else if ((key.readyOps() & SelectionKey.OP_READ)
            == SelectionKey.OP_READ) {
            // Read the data
            SocketChannel sc = (SocketChannel)key.channel();
  
            // Echo data
            int bytesEchoed = 0;
            while (true) {
              echoBuffer.clear();
  
              int number_of_bytes = sc.read(echoBuffer);
  
              if (number_of_bytes <= 0) {
                break;
              }
  
              echoBuffer.flip();
  
              sc.write(echoBuffer);
              bytesEchoed += number_of_bytes;
            }
  
            System.out.println("Echoed " + bytesEchoed + " from " + sc);
  
            it.remove();
          }
  
        }
      }
    }
  
    static public void main( String args[] ) throws Exception {
      if (args.length<=0) {
        System.err.println("Usage: java MultiPortEcho port [port port ...]");
        System.exit(1);
      }
  
      int ports[] = new int[args.length];
  
      for (int i=0; i<args.length; ++i) {
        ports[i] = Integer.parseInt(args[i]);
      }
  
      new MultiPortEcho(ports);
    }
  }

Compile this source, then launch it from the command-line with an invocation such as java MultiPortEcho 8005 8006. Once the MultiPortEchoer is running, start up a simple telnet or other terminal emulator running against ports 8005 and 8006. You will see that the program echoes back characters it receives -- and does it in a single Java thread!

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.

5. Character encoding and searching

The final feature of NIO that I want to introduce in this article is charset, a package for converting between different character encodings. Even before NIO, Java built in much of the same functionality through the getBytes method. charset is welcome, though, because it is more flexible than getBytes and easier to implement at a low architectural level, which yields superior performance. This is particularly valuable for searches that must be sensitive to the encoding, collation, and other characteristics of languages other than English.

Listing 4 shows an example of a conversion from Java's native Unicode character encoding to Latin-1.
Listing 4. Character encoding in NIO

String some_string = "This is a string that Java natively stores as Unicode.";
Charset latin1_charset = Charset.forName("ISO-8859-1");
CharsetEncode latin1_encoder = charset.newEncoder();
ByteBuffer latin1_bbuf = latin1_encoder.encode(CharBuffer.wrap(some_string));

Note that Charsets and channels are designed to work well together in order to ensure that programs requiring cooperation between memory mapping, asynchronous I/O, and encoding translation perform adequately.
Conclusion: Of course there's more

The purpose of this article has been to familiarize working Java developers with some of the main (and most useful) facilities of NIO and NIO.2. You can use the foundation established by the examples here to understand some of NIO's secondary methods; for instance, what you've learned about channels will help you make sense of NIO's Path facility for managing symbolic file-system links. See the Resources section as well, for a listing of more in-depth articles about the Java New Input/Output APIs.

From:
http://www.javaworld.com/article/2078654/core-java/java-se-five-ways-to-maximize-java-nio-and-nio-2.html

Java I/O and NIO [reproduced]的更多相关文章

  1. Java网络编程和NIO详解开篇:Java网络编程基础

    Java网络编程和NIO详解开篇:Java网络编程基础 计算机网络编程基础 转自:https://mp.weixin.qq.com/s/XXMz5uAFSsPdg38bth2jAA 我们是幸运的,因为 ...

  2. Java网络编程和NIO详解8:浅析mmap和Direct Buffer

    Java网络编程与NIO详解8:浅析mmap和Direct Buffer 本系列文章首发于我的个人博客:https://h2pl.github.io/ 欢迎阅览我的CSDN专栏:Java网络编程和NI ...

  3. Java网络编程和NIO详解9:基于NIO的网络编程框架Netty

    Java网络编程和NIO详解9:基于NIO的网络编程框架Netty 转自https://sylvanassun.github.io/2017/11/30/2017-11-30-netty_introd ...

  4. Java网络编程和NIO详解7:浅谈 Linux 中NIO Selector 的实现原理

    Java网络编程和NIO详解7:浅谈 Linux 中NIO Selector 的实现原理 转自:https://www.jianshu.com/p/2b71ea919d49 本系列文章首发于我的个人博 ...

  5. Java网络编程和NIO详解6:Linux epoll实现原理详解

    Java网络编程和NIO详解6:Linux epoll实现原理详解 本系列文章首发于我的个人博客:https://h2pl.github.io/ 欢迎阅览我的CSDN专栏:Java网络编程和NIO h ...

  6. Java网络编程和NIO详解5:Java 非阻塞 IO 和异步 IO

    Java网络编程和NIO详解5:Java 非阻塞 IO 和异步 IO Java 非阻塞 IO 和异步 IO 转自https://www.javadoop.com/post/nio-and-aio 本系 ...

  7. Java网络编程和NIO详解4:浅析NIO包中的Buffer、Channel 和 Selector

    Java网络编程与NIO详解4:浅析NIO包中的Buffer.Channel 和 Selector 转自https://www.javadoop.com/post/nio-and-aio 本系列文章首 ...

  8. Java网络编程和NIO详解2:JAVA NIO一步步构建IO多路复用的请求模型

    Java网络编程与NIO详解2:JAVA NIO一步步构建IO多路复用的请求模型 知识点 nio 下 I/O 阻塞与非阻塞实现 SocketChannel 介绍 I/O 多路复用的原理 事件选择器与 ...

  9. Java网络编程和NIO详解3:IO模型与Java网络编程模型

    Java网络编程和NIO详解3:IO模型与Java网络编程模型 基本概念说明 用户空间与内核空间 现在操作系统都是采用虚拟存储器,那么对32位操作系统而言,它的寻址空间(虚拟存储空间)为4G(2的32 ...

随机推荐

  1. POCO Controller 你这么厉害,ASP.NET vNext 知道吗?

    写在前面 阅读目录: POCO 是什么? 为什么会有 POJO? POJO 的意义 POJO 与 PO.VO 的区别 POJO 的扩展 POCO VS DTO Controller 是什么? 关于 P ...

  2. excel 日期/数字格式不生效需要但双击才会生效的解决办法

    原因: Excel2007设置过单元格格式后,并不能立即生效必须挨个双击单元格,才能生效.数据行很多.效率太低. 原因:主要是一些从网上拷贝过来的日期或数字excel默认为文本格式或特殊-中文数字格式 ...

  3. .Net多线程编程—预备知识

    1 基本概念 共享内存的多核架构:一个单独的封装包内封装了多个互相连接的未处理器,且所有内核都可以访问主内存.共享内存的多核系统的一些微架构,例如内核暂停功能,超频. 内核暂停功能:当使用内核不多的时 ...

  4. 基于netty http协议栈的轻量级流程控制组件的实现

    今儿个是冬至,所谓“冬大过年”,公司也应景五点钟就放大伙儿回家吃饺子喝羊肉汤了,而我本着极高的职业素养依然坚持留在公司(实则因为没饺子吃没羊肉汤喝,只能呆公司吃食堂……).趁着这一个多小时的时间,想跟 ...

  5. mybatis plugins实现项目【全局】读写分离

    在之前的文章中讲述过数据库主从同步和通过注解来为部分方法切换数据源实现读写分离 注解实现读写分离: http://www.cnblogs.com/xiaochangwei/p/4961807.html ...

  6. Web安全相关(四):过多发布(Over Posting)

    简介 过多发布的内容相对比较简单,因此,我只打算把原文中的一些关键信息翻译一下.原文链接如下: http://www.asp.net/mvc/overview/getting-started/gett ...

  7. duang~免费的学习视频来啦:学霸君之全栈测试

    学霸君向童鞋们推荐一款 同名学霸学习 视频教程 重点是完全免费收看学习噢!!! 今天 学霸君推荐腾讯课堂的学霸君之全栈测试 复制下方链接至腾讯课堂中报名学习 https://ke.qq.com/cou ...

  8. Linux主机上使用交叉编译移植u-boot到树莓派

    0环境 Linux主机OS:Ubuntu14.04 64位,运行在wmware workstation 10虚拟机 树莓派版本:raspberry pi 2 B型. 树莓派OS: Debian Jes ...

  9. BZOJ 2119: 股市的预测 [后缀数组 ST表]

    2119: 股市的预测 Time Limit: 10 Sec  Memory Limit: 259 MBSubmit: 331  Solved: 153[Submit][Status][Discuss ...

  10. Mono 3.2.3 Socket功能迎来一稳定的版本

    由于兴趣自己业余时间一直在搞.net下面的通讯应用,mono的存在得以让.NET程序轻松运行在Linux之下.不过经过多尝试Socket相关功能在Mono下的表现并不理想.不管性能还是吞吐能力方面离我 ...