Java之NIO

简介: Java之NIO

Java NIO是从Java 1.4版本开始引入的一个新的IO API,与传统IO 的主要区别

IO NIO
面向流(Stream Oriented 面向缓冲区(Buffer Oriente
阻塞IO(Blocking IO 非阻塞IO(Non Blocking I
选择器(Selector

Java NIO系统的核心在于:通道(Channel)和缓冲区(Buffer)。通道表示打开到 IO 设备(例如:文件、套接字)的连接。若需要使用 NIO 系统,需要获取用于连接 IO 设备的通道以及用于容纳数据的缓冲区。然后操作缓冲区,对数据进行处理。


也就是说:Channel 负责传输, Buffer 负责存储


一、缓冲区(Buffer):


在 Java NIO 中负责数据的存取。缓冲区就是数组。用于存储不同数据类型的数据


根据数据类型不同(boolean 除外),提供了相应类型的缓冲区:

ByteBuffer,CharBuffer,ShortBuffer,IntBuffer,LongBuffer,FloatBuffer, DoubleBuffer


缓冲区存取数据的两个核心方法:

put() : 存入数据到缓冲区中

get() : 获取缓冲区中的数据


缓冲区中的四个核心属性:

capacity : 容量,表示缓冲区中最大存储数据的容量。一旦声明不能改变。

limit : 界限,表示缓冲区中可以操作数据的大小。(limit 后数据不能进行读写)

position : 位置,表示缓冲区中正在操作数据的位置。

mark : 标记,表示记录当前 position 的位置。可以通过 reset() 恢复到 mark 的位置


Buffer在读写的时候有两个重要的方法

Buffer clear 清空缓冲区并返回对缓冲区的
Buffer flip 将缓冲区的界限设置为当前位置,并将当前位置充值为

比如说我们在利用通道进行复制文件的时候,常常会这样用到

      //②分配指定大小的缓冲区
      ByteBuffer buf = ByteBuffer.allocate(1024);
      //③将通道中的数据存入缓冲区中
      while(inChannel.read(buf) != -1){
        buf.flip(); //切换读取数据的模式
        //④将缓冲区中的数据写入通道中
        outChannel.write(buf);
        buf.clear(); //清空缓冲区
      }

先把通道中的数据读到缓冲区,假设缓冲区读到了一半的位置,用position方法就可得到当前正在操作数据的位置(512),使用flip方法切换到把buf的内容写入到通道模式,如果我们再用position方法就会得到位置为0,limit方法得到位置512,也就是说,我们只能把buf里面(0~512)个字节的数据写入到outChannel里面。


二 、通道(Channel):用于源节点与目标节点的连接。在 Java NIO 中负责缓冲区中数据的传输。Channel 本身不存储数据,因此需要配合缓冲区进行传输。


Java 为 Channel 接口提供的最主要实现类如下


FileChannel:用于读取、写入、映射和操作文件的通


DatagramChannel:通过 UDP 读写网络中的数据通


SocketChannel:通过 TCP 读写网络中的数


ServerSocketChannel:可以监听新进来的 TCP 连接,对每一个新进来的连接都会创建一个 SocketChanne


获取通道的一种方式是对支持通道的对象调用getChannel() 方法。支持通道的类如下


本地 IO:


FileInputStream


FileOutputStream


RandomAccess


网络IO:


DatagramSock


Socket


ServerSock


获取通道的其他方式是使用 Files 类的静态方法 newByteChannel() 获取字节通道。或者通过通道的静态方法 open() 打开并返回


指定通道。


三 、NIO 的非阻塞式网络通信


     传统的 IO 流都是阻塞式的。也就是说,当一个线程调用 read() 或 write()时,该线程被阻塞,直到有一些数据被读取或写入,该线程在此期间不能执行其他任务。因此,在完成网络通信进行 IO 操作时,由于线程会阻塞,所以服务器端必须为每个客户端都提供一个独立的线程进行处理,当服务器端需要处理大量客户端时,性能急剧下降。


      Java NIO 是非阻塞模式的。当线程从某通道进行读写数据时,若没有数据可用时,该线程可以进行其他任务。线程通常将非阻塞 IO 的空闲时间用于在其他通道上执行 IO 操作,所以单独的线程可以管理多个输入和输出通道。因此,NIO 可以让服务器端使用一个或有限几个线程来同时处理连接到服务器端的所有客户端。


使用 NIO 完成网络通信的三个核心:


1. 通道(Channel):负责连接


2. 缓冲区(Buffer):负责数据的存取


3. 选择器(Selector):是 SelectableChannel 的多路复用器。用于监控 SelectableChannel 的 IO 状况。利用 Selector

可使一个单独的线程管理多个 Channel。Selector 是非阻塞 IO 的核心。


所有连接的通道都要注册到选择器上,并指定监听事件,让选择器来统一管理。


可以监听的事件类型(可使用 SelectionKey 的四个常量表示):

读 : SelectionKey.OP_READ (1)

写 : SelectionKey.OP_WRITE (4)

连接 : SelectionKey.OP_CONNECT (8)

接收 : SelectionKey.OP_ACCEPT (16)


下面是一个网络通信的案例:服务端创建一个ServerSocketChannel用于监听客户端,并注册到选择器上,指定事件为接收事件,如果客户端的通道准备好了,请求连接,那么选择器就会进行处理,服务端会把该通道注册到选择器上,并指定时间为读事件。然后再迭代选择器里面的通道依次处理这些通道。


NIO 完成网络通信的案例:

public class TestNonBlockingNIO {
  //客户端
  @Test
  public void client() throws IOException{
    //1. 获取通道
    SocketChannel sChannel = SocketChannel.open(new InetSocketAddress("127.0.0.1", 9898));
    //2. 切换非阻塞模式
    sChannel.configureBlocking(false);
    //3. 分配指定大小的缓冲区
    ByteBuffer buf = ByteBuffer.allocate(1024);
    //4. 发送数据给服务端
    Scanner scan = new Scanner(System.in);
    while(scan.hasNext()){
      String str = scan.next();
      buf.put((new Date().toString() + "\n" + str).getBytes());
      buf.flip();
      sChannel.write(buf);
      buf.clear();
    }
    //5. 关闭通道
    sChannel.close();
  }
  //服务端
  @Test
  public void server() throws IOException{
    //1. 获取通道
    ServerSocketChannel ssChannel = ServerSocketChannel.open();
    //2. 切换非阻塞模式
    ssChannel.configureBlocking(false);
    //3. 绑定连接
    ssChannel.bind(new InetSocketAddress(9898));
    //4. 获取选择器
    Selector selector = Selector.open();
    //5. 将通道注册到选择器上, 并且指定“监听接收事件”
    ssChannel.register(selector, SelectionKey.OP_ACCEPT);
    //6. 轮询式的获取选择器上已经“准备就绪”的事件
    while(selector.select() > 0){
      //7. 获取当前选择器中所有注册的“选择键(已就绪的监听事件)”
      Iterator<SelectionKey> it = selector.selectedKeys().iterator();
      while(it.hasNext()){
        //8. 获取准备“就绪”的是事件
        SelectionKey sk = it.next();
        //9. 判断具体是什么事件准备就绪
        if(sk.isAcceptable()){
          //10. 若“接收就绪”,获取客户端连接
          SocketChannel sChannel = ssChannel.accept();
          //11. 切换非阻塞模式
          sChannel.configureBlocking(false);
          //12. 将该通道注册到选择器上
          sChannel.register(selector, SelectionKey.OP_READ);
        }else if(sk.isReadable()){
          //13. 获取当前选择器上“读就绪”状态的通道
          SocketChannel sChannel = (SocketChannel) sk.channel();
          //14. 读取数据
          ByteBuffer buf = ByteBuffer.allocate(1024);
          int len = 0;
          while((len = sChannel.read(buf)) > 0 ){
            buf.flip();
            System.out.println(new String(buf.array(), 0, len));
            buf.clear();
          }
        }
        //15. 取消选择键 SelectionKey
        it.remove();
      }
    }
  }
}
相关文章
|
2月前
|
监控 Java API
探索Java NIO:究竟在哪些领域能大显身手?揭秘原理、应用场景与官方示例代码
Java NIO(New IO)自Java SE 1.4引入,提供比传统IO更高效、灵活的操作,支持非阻塞IO和选择器特性,适用于高并发、高吞吐量场景。NIO的核心概念包括通道(Channel)、缓冲区(Buffer)和选择器(Selector),能实现多路复用和异步操作。其应用场景涵盖网络通信、文件操作、进程间通信及数据库操作等。NIO的优势在于提高并发性和性能,简化编程;但学习成本较高,且与传统IO存在不兼容性。尽管如此,NIO在构建高性能框架如Netty、Mina和Jetty中仍广泛应用。
56 3
|
2月前
|
存储 监控 Java
Java的NIO体系
通过本文的介绍,希望您能够深入理解Java NIO体系的核心组件、工作原理及其在高性能应用中的实际应用,并能够在实际开发中灵活运用这些知识,构建高效的Java应用程序。
63 5
|
7月前
|
Java 大数据
解析Java中的NIO与传统IO的区别与应用
解析Java中的NIO与传统IO的区别与应用
|
3月前
|
消息中间件 缓存 Java
java nio,netty,kafka 中经常提到“零拷贝”到底是什么?
零拷贝技术 Zero-Copy 是指计算机执行操作时,可以直接从源(如文件或网络套接字)将数据传输到目标缓冲区, 而不需要 CPU 先将数据从某处内存复制到另一个特定区域,从而减少上下文切换以及 CPU 的拷贝时间。
java nio,netty,kafka 中经常提到“零拷贝”到底是什么?
|
5月前
|
存储 网络协议 Java
Java NIO 开发
本文介绍了Java NIO(New IO)及其主要组件,包括Channel、Buffer和Selector,并对比了NIO与传统IO的优势。文章详细讲解了FileChannel、SocketChannel、ServerSocketChannel、DatagramChannel及Pipe.SinkChannel和Pipe.SourceChannel等Channel实现类,并提供了示例代码。通过这些示例,读者可以了解如何使用不同类型的通道进行数据读写操作。
Java NIO 开发
|
4月前
|
Java
让星星⭐月亮告诉你,Java NIO之Buffer详解 属性capacity/position/limit/mark 方法put(X)/get()/flip()/compact()/clear()
这段代码演示了Java NIO中`ByteBuffer`的基本操作,包括分配、写入、翻转、读取、压缩和清空缓冲区。通过示例展示了`position`、`limit`和`mark`属性的变化过程,帮助理解缓冲区的工作原理。
63 2
|
6月前
|
Java
"揭秘Java IO三大模式:BIO、NIO、AIO背后的秘密!为何AIO成为高并发时代的宠儿,你的选择对了吗?"
【8月更文挑战第19天】在Java的IO编程中,BIO、NIO与AIO代表了三种不同的IO处理机制。BIO采用同步阻塞模型,每个连接需单独线程处理,适用于连接少且稳定的场景。NIO引入了非阻塞性质,利用Channel、Buffer与Selector实现多路复用,提升了效率与吞吐量。AIO则是真正的异步IO,在JDK 7中引入,通过回调或Future机制在IO操作完成后通知应用,适合高并发场景。选择合适的模型对构建高效网络应用至关重要。
126 2
|
6月前
|
网络协议 C# 开发者
WPF与Socket编程的完美邂逅:打造流畅网络通信体验——从客户端到服务器端,手把手教你实现基于Socket的实时数据交换
【8月更文挑战第31天】网络通信在现代应用中至关重要,Socket编程作为其实现基础,即便在主要用于桌面应用的Windows Presentation Foundation(WPF)中也发挥着重要作用。本文通过最佳实践,详细介绍如何在WPF应用中利用Socket实现网络通信,包括创建WPF项目、设计用户界面、实现Socket通信逻辑及搭建简单服务器端的全过程。具体步骤涵盖从UI设计到前后端交互的各个环节,并附有详尽示例代码,助力WPF开发者掌握这一关键技术,拓展应用程序的功能与实用性。
214 0
|
7月前
|
安全 Java Linux
(七)Java网络编程-IO模型篇之从BIO、NIO、AIO到内核select、epoll剖析!
IO(Input/Output)方面的基本知识,相信大家都不陌生,毕竟这也是在学习编程基础时就已经接触过的内容,但最初的IO教学大多数是停留在最基本的BIO,而并未对于NIO、AIO、多路复用等的高级内容进行详细讲述,但这些却是大部分高性能技术的底层核心,因此本文则准备围绕着IO知识进行展开。
222 1
|
6月前
|
存储 网络协议 Java
【Netty 神奇之旅】Java NIO 基础全解析:从零开始玩转高效网络编程!
【8月更文挑战第24天】本文介绍了Java NIO,一种非阻塞I/O模型,极大提升了Java应用程序在网络通信中的性能。核心组件包括Buffer、Channel、Selector和SocketChannel。通过示例代码展示了如何使用Java NIO进行服务器与客户端通信。此外,还介绍了基于Java NIO的高性能网络框架Netty,以及如何用Netty构建TCP服务器和客户端。熟悉这些技术和概念对于开发高并发网络应用至关重要。
115 0