NIO同步非阻塞模型学习使用

简介: NIO同步非阻塞模型学习使用

别拿奋斗当借口,吃好才能继续走

NIO同步非阻塞模型

NIO 相关类都被放在 java.nio 包及子包下,并且对原 java.io 包中的很多类进行改写。

NIO 有三大核心部分:Channel( 通道) ,Buffer( 缓冲区), Selector( 选择器)

NIO 和 BIO 的比较

20200401134307494.png

BIO 以流的方式处理数据,而NIO以块的方式处理数据,块I/O的效率比流I/O高很多

BIO是阻塞的,NIO则是非阻塞的

BIO基于字节流和字符流进行操作,而NIO基于channel(通道)和Buffer(缓冲区)进行操作,数据总是从通道读取到缓冲区中,或者从缓冲区写入通道中。Selector(选择器)用于监听多个通道的事件(比如连接请求、事件到达等),因此使用单个线程就可以监听多个客户端通道。

NIO 三大核心

NIO三大核心:Channel通道、Buffer缓冲区、Selector选择器

Buffer缓冲区

缓冲区本质上是一块可以写入数据的内存块,底层是一个数组,这块内存被包装为NIO Buffer对象,并提供了一组方法,用来方便的访问该块内存。相比较直接对数组的操作,Buffer API更加容易操作和管理。

Channel(通道)

Java NIO的通道类似流,但又有些不同:既可以从通道中读取数据,又可以写数据到通道。但流的(input或output)读写通常是单向的,通道可以非阻塞读取和写入通道,通道可以支持读取和写入缓冲区,也支持异步读写。每个channel都会对应一个buffer

Selector选择器

Selector是一个java NIo组件,可以能够检查一个或多个NIO通道,并确定哪些通道已经准备好进行读取或写入。Selector会根据不同的事件,在各个通道上切换,这样,一个单独的线程可以管理多个channel,从而管理多个网络连接,提高效率。一个线程对应一个Selector,一个Selector对应多个channel(连接)

20200401134307494.png


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

NIO非阻塞式网络通信入门案例

需求:服务端接收客户端的连接请求,并接收多个客户端发送过来的事件。

代码案例

服务端:

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.Iterator;
/**
* @PackageName: com.netty.nio.buffer.demo2
* @author: youjp
* @create: 2021-01-04 09:59
* @description: TODO NIO模式下的服务端
* @Version: 1.0
*/
public class Server {
    public static void main(String[] args) throws IOException {
        //1,获取通道
        ServerSocketChannel channel = ServerSocketChannel.open();
        //2.切换到非阻塞模式
        channel.configureBlocking(false);
        //3.绑定连接,绑定8888端口
        channel.bind(new InetSocketAddress(8888));
        //4.获取选择器
        Selector selector = Selector.open();
        //5.讲通道注册到获取的选择器上,并指定监听事件,这里刚开始为连接
        channel.register(selector, SelectionKey.OP_ACCEPT);
        System.out.println("-----服务端准备就绪-----");
        //6.轮询选择器获取已经"准备就绪的事件"
        while (selector.select() > 0) {
            //7.获取当前选择器中所有注册的“选择键(已就绪的监听事件)”
            Iterator<SelectionKey> it = selector.selectedKeys().iterator();
            while (it.hasNext()) {
                //8.获取准备“就绪”事件
                SelectionKey sk = it.next();
                //判断具体事件
                if (sk.isAcceptable()) {
                    //若为接收就绪,获取客户端连接
                    SocketChannel sChannel = channel.accept();
                    sChannel.configureBlocking(false);//设置非阻塞模式
                    sChannel.register(selector, SelectionKey.OP_READ);//以读事件,将该通道注册到选择器上,
                    System.out.println("--通道准备就绪------"+sChannel.getRemoteAddress()+"------");
                } else if (sk.isReadable()) { //读准备就绪
                    //获取当前选择器上“读就绪”状态的通道
                    SocketChannel ch = (SocketChannel) sk.channel();
                    //使用缓冲区读取数据
                    ByteBuffer buffer = ByteBuffer.allocate(1024);
                    int len = 0;
                    while ((len = ch.read(buffer)) > 0) {
                        buffer.flip();//切换为读取模式
                        System.out.println(new String(buffer.array(), 0, len));
                        buffer.clear();
                    }
                }
                //取消当前选择键
                it.remove();
            }
        }
    }
}

客户端

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SocketChannel;
import java.text.SimpleDateFormat;
import java.util.Scanner;
/**
* @PackageName: com.netty.nio.buffer.demo2
* @author: youjp
* @create: 2021-01-04 09:59
* @description: NIo模式下的客户端
* @Version: 1.0
*/
public class Client {
    public static void main(String[] args) throws IOException {
        //1.获取通道
        SocketChannel sh=SocketChannel.open(new InetSocketAddress("127.0.0.1",8888));
        //2.设置为非阻塞模式
        sh.configureBlocking(false);
        //3.设置缓冲区
        ByteBuffer buffer= ByteBuffer.allocate(1024);
        //4.写入数据发给服务端
        Scanner scan=new Scanner(System.in);
        while (scan.hasNext()){
            String str=scan.nextLine();
            buffer.put((new SimpleDateFormat("yyyy/MM/dd HH:mm:ss").format(System.currentTimeMillis())
                    + "\n" + str).getBytes());
            buffer.flip();
            sh.write(buffer);
            buffer.clear();
        }
        //5.关闭通道
        sh.close();
    }
}

有兴趣的老爷,可以关注我的公众号【一起收破烂】,回复【006】获取2021最新java面试资料以及简历模型120套哦~


相关文章
|
存储 Java API
【面试题精讲】javaIO模型之NIO
【面试题精讲】javaIO模型之NIO
|
4月前
|
安全 Java Linux
(七)Java网络编程-IO模型篇之从BIO、NIO、AIO到内核select、epoll剖析!
IO(Input/Output)方面的基本知识,相信大家都不陌生,毕竟这也是在学习编程基础时就已经接触过的内容,但最初的IO教学大多数是停留在最基本的BIO,而并未对于NIO、AIO、多路复用等的高级内容进行详细讲述,但这些却是大部分高性能技术的底层核心,因此本文则准备围绕着IO知识进行展开。
165 1
|
5月前
|
Java 视频直播 数据库连接
Java I/O 模型详解:BIO、NIO 与 AIO 的特性与应用
Java I/O 模型详解:BIO、NIO 与 AIO 的特性与应用
66 2
|
5月前
|
存储 监控 Java
深入探索Java BIO与NIO输入输出模型:基于文件复制和socket通信
深入探索Java BIO与NIO输入输出模型:基于文件复制和socket通信
|
6月前
|
监控 Java
Java一分钟之-NIO:非阻塞IO操作
【5月更文挑战第14天】Java的NIO(New IO)解决了传统BIO在高并发下的低效问题,通过非阻塞方式提高性能。NIO涉及复杂的选择器和缓冲区管理,易出现线程、内存和中断处理的误区。要避免这些问题,可以使用如Netty的NIO库,谨慎设计并发策略,并建立标准异常处理。示例展示了简单NIO服务器,接收连接并发送欢迎消息。理解NIO工作原理和最佳实践,有助于构建高效网络应用。
79 2
|
6月前
|
存储 监控 Java
Java nio非阻塞io
Java nio非阻塞io
|
6月前
|
网络协议 Java Linux
用Java来实现BIO和NIO模型的HTTP服务器(二) NIO的实现
用Java来实现BIO和NIO模型的HTTP服务器(二) NIO的实现
|
缓存 网络协议 前端开发
从BIO到NIO在到Netty线程模型详解
从BIO到NIO在到Netty线程模型详解
191 1
|
Java 容器
【深入研究NIO与Netty线程模型的源码】
【深入研究NIO与Netty线程模型的源码】
|
网络协议 Java
【JAVA基础】- 同步非阻塞模式NIO详解
【JAVA基础】- 同步非阻塞模式NIO详解
154 0