天天看点

Java高性能编程之NIO三大核心理念NIO三大核心理念

NIO三大核心理念

首先介绍NIO中三个核心组件

  • Buffer缓冲区
  • Channel通道
  • Selector选择器

一、Buffer缓冲区

Java高性能编程之NIO三大核心理念NIO三大核心理念

1.Buffer 三个重要属性:

  • capacity容量:作为一个内存块,Buffer具有一定的固定大小,也成为“容量”
  • position位置:写入模式时代表写数据的位置。读取模式时,代表读取数据的位置
  • limit限制:写入模式,限制等于buffer的容量。读取模式下,limit等于写入的数据量

    //注意区分不同模式下的含义。

2. ByteBuffer内存类型

  • 直接内存(direct堆外内存):在JVM之外向物理内存直接申请内存

    进行IO或文件IO时比heapBuffer少一次拷贝

ByteBuffrt directByteBuffer = ByteBuffer.allocateDirect(noBNytes);

优点:

1、进行IO或文件IO时比heapBuffer少一次拷贝。(file/socket -> OS memory -> jvm heap)

2、在GC范围之外,降低GC压力,但实现了自动管理。DirextByteBuffer类提供Cleaner对象(PhantomReference),Cleaner被GC前会执行clean方法,触发DirectByteBuffer中定义的Deallocator。

  • 非直接内存(heap堆内存):在JVM的申请内存

建议:性能确实可观的时候才去使用;分配给大型、长寿命;(网络传输、文件读写场景)

通过虚拟机参数MaxDirectMemorySize限制大小,防止耗尽整个机器内存

二、Channel: 通道

和标准的IO Stream区别:在一个通道内进行读取和写入时stream通常是单向的(input和output),可以非阻塞读取和写入通道,通道始终读取或写入缓冲区,channel的API涵盖了UDP/TCP网络和文件IO。(FileCjannel,DatagramCjannel,SocketChannel,ServerSocketChannel)

SocketChannel:用于创建TCP连接,类似java.net.Socket.有两种创建的方式:

1、客户端主动发起和服务的连接。

2、服务端获取新的连接

  • SockerChannel:客户端

//客户端主动发起连接的方式

SocketChannel socketChannel = SocketChannel.open();

//设置为非阻塞模式

socketChannel.configureBlocking(false);

//创建一个端口和ip

socketChannel.connect(new InetSocketAddress(“htttp:163.com”,80));

//发送请求数据 - 向通道写入数据

socketChannel.write(byteBuffer);

//读取服务端返回 - 读取缓冲区的数据

int butesRead = socketChannel.read(byteBuffer);

//关闭连接

socketChannel.close();

write写:非阻塞,write()在尚未写入任何内容可能就返回了。需要在循环中调用

read读:非阻塞,read()方法可能直接返回而根本不读取任何数据,根据返回的int值判断读取了多少字节

  • ServerSocketChannel:服务端

//创建网络服务端

ServerSocketChannel serverSockerChannel = ServerSocketChannel.open();

//设为非阻塞模式

serverSocletChannel.configureBlocking(false);

//绑定端口

serverSocletChannel.socket().bind(new InetSocketAddress(8080));

while(true){

SocketChannel soccketChannel = serverSocletChannel.accept();

if(socketChannel != null){

//TCP请求 读取/响应

}

}

注:serverSocletChannel.accept()如果该通道处于非阻塞,如果没有挂起的连接则该方法立即返回null。

所以必须检查返回的对象是否为空

三、Selector:选择器

  • Selector是一个javaNIO 组件,可以检查一个或多个NIO通道,并确定哪些通道已经准备好进行读取或写入。实现单个线程可以管理多个通道,从而管理多个网络连接。核心概念是事件驱动机制。
  • 一个线程使用Selector监听多个channel的不同事件:

    四种事件分别对应SelectionKey四个常量:

Connect:连接(Selector.OP_CONNECT)
    客户端与服务端建立连接,客户端触发事件
    Accept: 准备就绪(OP_ACCEPT)
    服务端检测到客户端连接请求,服务端触发事件
    Read:   读取(OP_READ)
    客户端与服务端建立连接之后读取操作,双端触发事件
    Write:  写入(OP_WRITE)
    客户端与服务端建立连接之后写入操作,双端触发事件
           

NIO对比BIO

Java高性能编程之NIO三大核心理念NIO三大核心理念

四、NIO与多线程结合的改进方案

  • mainReactor接收->分发给subReactor读写->具体业务逻辑分发给单独的线程池处理

总结

NIO应用于网络应用开发还是比较繁琐,要想将性能提升,还需要和多线程技术结合起来。
因为网络编程本身的复杂性,以及JDK API开发的使用难度较高, 所以在开源社区中,涌出
来很多对JDK NIO进行封装、增强后的网络编程框架,例如:Netty、Mina等。
           

继续阅读